class Mobile(): """ """ def __init__(self, android_serial = None): # logger.info("Importing Android library") # print "Importing Android library" # clm.message("Importing Android library") self.adb = ADB(android_serial) self.device = Device(android_serial) self.test_helper = TestHelper(android_serial) def set_serial(self, android_serial): """ Set device serial """ self.adb = ADB(android_serial) self.device = Device(android_serial) self.test_helper = TestHelper(android_serial) def get_info(self): """ Retrieve the device info """ return self.device.info #Key Event Actions of the device """ Turn on/off screen """ def turn_on_screen(self): """ Turn on screen """ self.device.screen.on() def turn_off_screen(self): """ Turn off screen """ self.device.screen.off() def wakeup_the_device(self): """ wakeup the device """ self.device.wakeup() """ Press hard/soft key """ def press_key(self, *key): """ press *key* keycode """ self.device.press(*key) def press_home(self): """ press home key """ self.device.press.home() def press_back(self): """ press back key """ self.device.press.back() def press_left(self): """ press left key """ self.device.pres.left() def press_right(self): """ press right key """ self.device.press.right() def press_up(self): """ press up key """ self.device.press.up() def press_down(self): """ press down key """ self.device.press.down() def press_center(self): """ press center key """ self.device.press.center() def press_menu(self): """ press menu key """ self.device.press.menu() def press_search(self): """ press search key """ self.device.press.search() def press_enter(self): """ press enter key """ self.device.press.enter() def press_delete(self): """ press delete key """ self.device.press.delete() def press_recent(self): """ press recent key """ self.device.press.recent() def press_volume_up(self): """ press volume up key """ self.device.press.volume_up() def press_volume_down(self): """ press volume down key """ self.device.press.volume_down() def press_camera(self): """ press camera key """ self.device.press.camera() def press_power(self): """ press power key """ self.device.press.power() #Gesture interaction of the device def click(self, x, y): """ click (x, y) on screen """ self.device.click(x, y) def swipe(self, sx, sy, ex, ey, steps=10): """ swipe from (sx, sy) to (ex, ey) with steps """ self.device.swipe(sx, sy, ex, ey, steps) # Swipe from the center of the ui object to its edge def swipe_left(self, obj, steps=10): """ swipe the *obj* from center to left """ obj.swipe.left(steps=steps) def swipe_right(self, obj, steps=10): """ swipe the *obj* from center to right """ obj.swipe.right(steps=steps) def swipe_top(self, obj, steps=10): """ swipe the *obj* from center to top """ obj.swipe.top(steps=steps) def swipe_bottom(self, obj, steps=10): """ swipe the *obj* from center to bottom """ obj.swipe.bottom(steps=steps) def drag(self,sx, sy, ex, ey, steps=10): """ drag from (sx, sy) to (ex, ey) with steps """ self.device.drag(sx, sy, ex, ey, steps) #Wait until the specific ui object appears or gone # wait until the ui object appears def wait_for_exists(self, timeout=0, *args, **attribute): """ true means the object which has *attribute* exist false means the object does not exist in the given timeout """ return self.device(**attribute).wait.exists(timeout=timeout) # wait until the ui object gone def wait_until_gone(self, timeout=0, *args, **attribute): """ true means the object which has *attribute* disappear false means the object exist in the given timeout """ return self.device(**attribute).wait.gone(timeout=timeout) def wait_for_object_exists(self, obj, timeout=0): """ true means the object exist false means the object does not exist in the given timeout """ return obj.wait.exists(timeout=timeout) # wait until the ui object gone def wait_until_object_gone(self, obj, timeout=0): """ true means the object disappear false means the object exist in the given timeout """ return obj.wait.gone(timeout=timeout) # Perform fling on the specific ui object(scrollable) def fling_forward_horizontally(self, obj): """ return whether the object can be fling or not """ return obj.fling.horiz.forward() def fling_backward_horizontally(self, obj): """ return whether the object can be fling or not """ return obj.fling.horiz.backward() def fling_forward_vertically(self, obj): """ return whether the object can be fling or not """ return obj.fling.vert.forward() def fling_backward_vertically(self, obj): """ return whether the object can be fling or not """ return obj.fling.vert.backward() # Perform scroll on the specific ui object(scrollable) def scroll_to_beginning_vertically(self, obj, steps=10): """ """ return obj.scroll.vert.toBeginning(steps=steps) def scroll_forward_horizontally(self, obj, steps=10): """ return whether the object can be fling or not """ return obj.scroll.horiz.forward(steps=steps) def scroll_backward_horizontally(self, obj, steps=10): """ return whether the object can be fling or not """ return obj.scroll.horiz.backward(steps=steps) def scroll_to_horizontally(self, obj, *args,**attribute): """ return whether the object can be fling or not """ return obj.scroll.horiz.to(**attribute) def scroll_forward_vertically(self, obj, steps=10): """ return whether the object can be fling or not """ return obj.scroll.vert.forward(steps=steps) def scroll_backward_vertically(self, obj, steps=10): """ return whether the object can be fling or not """ return obj.scroll.vert.backward(steps=steps) def scroll_to_vertically(self, obj, *args, **attribute): """ return whether the object can be fling or not """ msg = '' for key, value in attribute.iteritems(): msg += ' %s=%s ' % (key, value) print msg # print 'args:' + args[0] return obj.scroll.vert.to(**attribute) #Screen Actions of the device def screenshot(self, scale=None, quality=None): """ Take a screenshot of device and log in the report with timestamp """ output_dir = BuiltIn().get_variable_value('${OUTPUTDIR}') ts = time.time() st = datetime.datetime.fromtimestamp(ts).strftime('%Y%m%d%H%M%S') screenshot_path = '%s%s%s.png' % (output_dir, os.sep, st) self.device.screenshot(screenshot_path, scale, quality) logger.info('\n<a href="%s">%s</a><br><img src="%s">' % (screenshot_path, st, screenshot_path), html=True) #Watcher # def register_click_watcher(self, watcher_name, attributes, *condition_list): # """ # The watcher click on the object which has the attributes when conditions match # """ # print type(attributes) # watcher = self.device.watcher(watcher_name) # for condition in condition_list: # watcher.when(**condition) # watcher.click(**attributes) # self.device.watchers.run() # print 'register watcher:%s' % watcher_name # return def __unicode_to_dict(self, a_unicode): a_dict = dict() dict_item_count = a_unicode.count('=') for count in range(dict_item_count): equal_sign_position = a_unicode.find('=') comma_position = a_unicode.find(',') a_key = a_unicode[0:equal_sign_position] if comma_position == -1: a_value = a_unicode[equal_sign_position + 1:] else: a_value = a_unicode[equal_sign_position + 1:comma_position] a_unicode = a_unicode[comma_position + 1:] a_dict[a_key] = a_value return a_dict def register_click_watcher(self, watcher_name, attributes, *condition_list): """ The watcher click on the object which has the *attributes* when conditions match """ watcher = self.device.watcher(watcher_name) for condition in condition_list: watcher.when(**self.__unicode_to_dict(condition)) watcher.click(**self.__unicode_to_dict(attributes)) self.device.watchers.run() def register_press_watcher(self, watcher_name, press_keys, *condition_list): """ The watcher perform *press_keys* action sequentially when conditions match """ def unicode_to_list(a_unicode): a_list = list() comma_count = a_unicode.count(',') for count in range(comma_count + 1): comma_position = a_unicode.find(',') if comma_position == -1: a_list.append(str(a_unicode)) else: a_list.append(a_unicode[0:comma_position]) a_unicode = a_unicode[comma_position + 1:] return a_list watcher = self.device.watcher(watcher_name) for condition in condition_list: watcher.when(**self.__unicode_to_dict(condition)) watcher.press(*unicode_to_list(press_keys)) self.device.watchers.run() def remove_watchers(self, watcher_name = None): """ remove watcher with *watcher_name* or remove all watchers """ if watcher_name == None: self.device.watchers.remove() else: self.device.watchers.remove(watcher_name) def list_all_watchers(self): """ return the watcher list """ return self.device.watchers #Selector def get_object(self, *args, **attribute): """ get the ui object with attribute *attribute* """ msg = '' for key, value in attribute.iteritems(): msg += ' %s=%s ' % (key, value) print msg return self.device(*args, **attribute) def get_info_of_object(self, obj): """ return info dictionary of the *obj* The info example: { u'contentDescription': u'', u'checked': False, u'scrollable': True, u'text': u'', u'packageName': u'com.android.launcher', u'selected': False, u'enabled': True, u'bounds': { u'top': 231, u'left': 0, u'right': 1080, u'bottom': 1776 }, u'className': u'android.view.View', u'focusable': False, u'focused': False, u'clickable': False, u'checkable': False, u'chileCount': 1, u'longClickable': False, u'visibleBounds': { u'top': 231, u'left': 0, u'right': 1080, u'bottom': 1776 } } """ return obj.info def click_on(self, *args, **attribute): """ click on the object with *attribute* """ self.device(**attribute).click() def long_click_on(self, *args, **attribute): """ click on the object with *attribute* """ self.device(**attribute).long_click() def call(self, obj, method, *args, **attribute): func = getattr(obj, method) return func(**attribute) def set_text(self, text, *args, **attribute): """ set *text* to the Component which has the *attribute* """ self.device(**attribute).set_text(text) def clear_text(self, *args, **attributes): """ Clear text of the component with *attributes* """ while True: target = self.device(**attributes) text = target.info['text'] target.clear_text() remain_text = target.info['text'] if text == '' or remain_text == text: break # Other feature def sleep(self, time): """ sleep(no action) for *time* (in millisecond) """ target = 'wait for %s' % str(time) self.device(text=target).wait.exists(timeout=time) def install(self, apk_path): self.adb.cmd('install "%s"' % apk_path) def uninstall(self, package_name): self.adb.cmd('uninstall %s' % package_name) def type(self, text): """ Type *text* at current focused component """ self.test_helper.send_set_text_cmd(text) def foo(self): pass # logger.info('\nGot arg %s %s' % (output_dir, st), also_console=True) # clm = CommandLineWriter() # output some messages on console # clm.message(' ') # clm.message(u'中文') # clm.message(u'2----------2') def test(self): pass
class uiAutomator(object): def __init__(self): self.device = None def getDeviceInstance(self): deviceId = self.getDeviceID() if deviceId is not None: self.device = Device(deviceId) def getDeviceID(self): deviceId = None cmd = "devices" output = command.executeCommandOnDevice(cmd) if output is not None: for line in output.splitlines(): reObj = re.search(r'(\w+).*device\b', line) if reObj: deviceId = reObj.group(1).strip() return deviceId def rootAndRemount(self): self.root() sleep(2) self.remount() def root(self): cmd = "root" command.executeCommandOnDevice(cmd) def remount(self): cmd = "remount" command.executeCommandOnDevice(cmd) def writeToFile(self,filePath, fileContent, mode='w'): try: with open(filePath,mode) as f: f.write(fileContent) except Exception as e: print("Error: unable to write content to a file") print(e.__str__()) def collectLogcat(self,filePath): cmd = "logcat" logcatContent = command.executeCommandOnDevice(cmd) if logcatContent is not None: self.writeToFile(filePath,logcatContent,'w') else: print("logcat is not collected properly") def collectDmesgLogs(self,filePath): cmd = "shell dmesg" fileContent = command.executeCommandOnDevice(cmd) if fileContent is not None: self.writeToFile(filePath,fileContent) else: print("dmesg log is not collected properly") def pushFiles(self,source,destination): cmd = "push {} {}".format(source,destination) command.executeCommandOnDevice(cmd) def pullFiles(self,source,destination): if self.doesResourceExists(source): cmd = "pull {} {}".format(source,destination) command.executeCommandOnDevice(cmd) else: print("Resource doesn't exists on the device, Hence pulling failed") def reboot(self): cmd = "reboot" command.executeCommandOnDevice(cmd) def installApp(self,apkPath): cmd = "install -r -g {}".format(apkPath) command.executeCommandOnDevice(cmd) def unInstallApp(self, packageName): cmd = "uninstall {}".format(packageName) command.executeCommandOnDevice(cmd) def installAPKs(self,apksPath): for apkFile in os.listdir(apksPath): if apkFile.endswith('.apk'): apkFilePath = os.path.join(apksPath,apkFile) self.installApp(apkFilePath) def doesResourceExists(self, filePath): cmd = "ls {}".format(filePath) output = command.executeCommandOnDevice(cmd) if 'No such file or directory' in output: return False return True def deleteResourceFromDevice(self,resourcePath): cmd = "shell rm -rf {}".format(resourcePath) command.executeCommandOnDevice(cmd) def captureScreenshot(self,imageFileName): imageFilePath = "/scard/{}".format(imageFileName) cmd = "shell screencap -p {}".format(imageFilePath) command.executeCommandOnDevice(cmd) def openAppMenu(self): self.device.press.home() self.swipeUp() def getCoOrdinates(self, xPercentage, yPercentage): x = (self.device.info['displayWidth']*xPercentage)/100 y = (self.device.info['displayHeight']*yPercentage)/100 return x,y def swipeUp(self): x1, y1 = self.getCoOrdinates(50, 75) x2, y2 = self.getCoOrdinates(50, 25) self.device.swipe(x1, y1, x2, y2) def swipeDown(self): x1, y1 = self.getCoOrdinates(50, 25) x2, y2 = self.getCoOrdinates(50, 75) self.device.swipe(x1, y1, x2, y2) def scrollUp(self, speed=60): x1, y1 = self.getCoOrdinates(50, 75) x2, y2 = self.getCoOrdinates(50, 25) cmd = "shell input touchscreen swipe {} {} {} {} {}".format(x1,y1,x2,y2,speed) command.executeCommandOnDevice(cmd) def scrollDown(self,speed=60): x1, y1 = self.getCoOrdinates(50, 25) x2, y2 = self.getCoOrdinates(50, 75) cmd = "shell input touchscreen swipe {} {} {} {} {}".format(x1,y1,x2,y2,speed) command.executeCommandOnDevice(cmd) def dragUp(self): x1, y1 = self.getCoOrdinates(50, 75) x2, y2 = self.getCoOrdinates(50, 25) self.device.drag(x1, y1, x2, y2) def dragDown(self): x1, y1 = self.getCoOrdinates(50, 25) x2, y2 = self.getCoOrdinates(50, 75) self.device.drag(x1, y1, x2, y2) def clickUsingText(self, textObj, className=None, instance=0): if className is None: self.device(text=textObj,instance=instance).click.wait() sleep(1) else: self.device(text=textObj, className= className, instance=instance).click.wait() def clearText(self, textObj, instance=0): self.device(text=textObj, instance=instance).clear_text() def setText(self, textObj, text, instance=0): self.device(text=textObj, instance=instance).set_text(text) sleep(1) def pressDown(self): self.device.press.down() sleep(1) def pressEnter(self): self.device.press.enter() sleep(1) def scrollAndClickAnElement(self, textObj, className=None, instance=0): count = 0 while count <=20: if self.isElementwithTextExists(textObj): self.clickUsingText(textObj, className, instance) break else: self.scrollUp(500) def isElementwithTextExists(self,textObj): if self.device(text=textObj).exists: return True return False def checkAndClickUsingText(self, textObj, instance=0): counter = 0 while counter <= 5: if self.isElementwithTextExists(textObj): self.clickUsingText(textObj,instance) sleep(2) break else: sleep(1) counter += 1 return False def isElementExistsWithDescription(self,descriptionObj): if self.device(description=descriptionObj).exists: return True return False def clickUsingDescription(self, descriptionObj, className=None, instance=0): if className is None: self.device(text=descriptionObj,instance=instance).click.wait() sleep(1) else: self.device(text=descriptionObj, className= className, instance=instance).click.wait() def checkAndClickUsingDescription(self, descriptionObj, instance=0): counter = 0 while counter <= 5: if self.isElementExistsWithDescription(descriptionObj): self.clickUsingDescription(descriptionObj, instance) sleep(2) break else: sleep(1) counter += 1 return False def isElementExistsWithResourceId(self, resourceIdObj): if self.device(resourceId=resourceIdObj).exists: return True return False def clickUsingResourceId(self, resourceIdObj, className=None, instance=0): if className is None: self.device(resourceId=resourceIdObj, instance=instance).click.wait() sleep(1) else: self.device(resourceId=resourceIdObj, className=className, instance=instance).click.wait() def checkAndClickUsingResourceId(self, resourceIdObj, instance=0): counter = 0 while counter <= 5: if self.isElementExistsWithResourceId(resourceIdObj): self.clickUsingResourceId(resourceIdObj, instance) sleep(2) break else: sleep(1) counter += 1 return False def getDeviceProperty(self,property): cmd = "shell getprop" output = command.executeCommandOnDevice(cmd) if output is not None: lines = output.splitlines() for line in lines: if property in line: (key,value) = line.split(':') patternObj = re.search(r'\[(.*)\]',value) if patternObj: return patternObj.group(1) else: print("property is not found in getprop list") return None def getDeviceBrand(self): brand = self.getDeviceProperty('ro.product.brand') print(brand) def getDeviceModel(self): model = self.getDeviceProperty('ro.product.model') print(model) def getInstalledApps(self): cmd = "shell pm list packages" packageList = command.executeCommandOnDevice(cmd) if packageList is not None: return packageList def isApplicationInstalled(self, packageName): packageList = self.getInstalledApps() if packageList is not None: packageLines = packageList.splitlines() for line in packageLines: if packageName in line: patternObj = re.search(r'package:(.*)',line) if patternObj: pkgName = patternObj.group(1) if pkgName == packageName: return True return False
class UiTestLib(object): """Ui Test Lib """ def __init__(self, serial=None): """ """ logger.info('<p>Device=%s>' % serial, html=True) print '<p>Device=%s>' % serial self._result = '' self.starttime = 0 self.d = Device(serial) self.adb = Adb(serial) self.debug = 'True' def set_debugable(flag): self.debug = flag def set_serial(self, serial): """Specify given *serial* device to perform test. or export ANDROID_SERIAL=CXFS42343 if you have many devices connected but you don't use this interface When you need to use multiple devices, do not use this keyword to switch between devices in test execution. And set the serial to each library. Using different library name when importing this library according to http://robotframework.googlecode.com/hg/doc/userguide/RobotFrameworkUserGuide.html?r=2.8.5. Examples: | Setting | Value | Value | Value | | Library | UiTestLib | WITH NAME | Mobile1 | | Library | UiTestLib | WITH NAME | Mobile2 | And set the serial to each library. | Test Case | Action | Argument | | Multiple Devices | Mobile1.Set Serial | device_1's serial | | | Mobile2.Set Serial | device_2's serial | """ self.d = Device(serial) self.adb = Adb(serial) def logmsg(self, msg): if self.debug == 'True': print msg def exe_adb_command(self, cmd): """ Execute adb *cmd* Examples: | Exe Adb Command | shell getprop | """ return self.adb.cmd(cmd).wait() def exe_adb_and_result(self, cmd): """Execute adb *cmd* and return lines of the command""" lproc = self.adb.cmd(cmd) lproc.poll() lines = lproc.stdout.readlines() return lines def get_device_info(self): """Get Device information return info dictionary """ return self.d.info def light_screen(self): """Light screen by wakeup. Examples: | Action | |Light screen| Use `Light screen` to light screen. """ self.d.wakeup() self._result = self.d.press.home() def open_application(self, appname): """Open application by it name `appname`. Example: | Action | Argument | | Open application | "com.android.settings/com.android.settings.Settings" | """ appname = 'shell am start -n ' + appname print 'Open Application:', appname self._result = self.exe_adb_command(appname) def click_text(self, text, instance=0): """Click text label on screen instance=0 is default, change when you needed. Example: | Action | Argument | Argument | | Click Text | text | instance | """ return self.d(text=text, instance=instance).click.wait() def long_click_text(self, text, instance=0): """ Long Click text label on screen, *text* and *instance=0* Example: | Action | Argument | Argument | | Long Click Text | text | instance | """ return self.d(text=text, instance=instance).long_click() def long_click_ui(self, **selectors): """ Long Click on **selectors** Selector supports below parameters. Refer to UiSelector java doc for detailed information. text, textContains, textMatches, textStartsWith className, classNameMatches description, descriptionContains, descriptionMatches, descriptionStartsWith checkable, checked, clickable, longClickable scrollable, enabled,focusable, focused, selected packageName, packageNameMatches resourceId, resourceIdMatches index, instance Example: | Action | Argument | Argument | Argument | | Long Click UI | text=XXXX | className=XXX.xxxx | resourceId=xxxxxx | """ return self.d(**selectors).long_click() def text_display_on_screen_contains(self, text): """Verify text display on screen Example: | Action | Argument | |Text display on screen is| text | """ if self.d(text=text).exists: self._result = True return True else: self._result = False return False def object_display_on_screen(self, obj, timeout=5000): """ Verify *obj* UiObject display on screen return to self._result Example: | Action | Argument | |Object display on screen | obj | """ if obj.wait.exists(timeout): self._result = True return True else: self._result = False return False def assert_expectation(self, expect, actual): """ Assert Expectation and actual value Example: | Action | args | args | | Assert Expectation | 324324 | ${actual} | """ if str(expect) != str(actual): raise AssertionError( 'Actual result is = %s, but expectation is: %s' % (str(actual), str(expect))) def assert_true(self, condition): """ Assert True of *condition Example: |Assert True | condition | """ if str(condition) != 'True': #because only string from robotframework raise AssertionError('Result is = %s' % str(condition)) def assert_result_true(self): """ Assert True of *self._result Example: |Assert True | """ if self._result != True: raise AssertionError('Result is = %s' % str(self._result)) def wait_for_ui_exists(self, timeout, **selectors): """ Return True if Selector is to identify specific ui object in current window. # To seleted the object ,text is 'Clock' and its className is 'android.widget.TextView' wait_for_ui_exists(text='Clock', className='android.widget.TextView') Selector supports below parameters. Refer to UiSelector java doc for detailed information. text, textContains, textMatches, textStartsWith className, classNameMatches description, descriptionContains, descriptionMatches, descriptionStartsWith checkable, checked, clickable, longClickable scrollable, enabled,focusable, focused, selected packageName, packageNameMatches resourceId, resourceIdMatches index, instance Examples: | Action | Argument | Argument | Argument | Argument | |Wait For UI Exists | timeout | text=XXXX | className=XXX.xxxx | resourceId=xxxxxx | """ self._result = self.d(**selectors).wait.exists(timeout=int(timeout)) return self._result def wait_and_click(self, timeout, **selectors): """Wait for uiselector and click""" if self.d(**selectors).wait.exists(timeout=int(timeout)): self.d(**selectors).click() def assert_ui_exists(self, **selectors): """ Assert UiObject appear on the screen Examples: | Action | Argument | Argument | Argument | Argument | |Assert UI Exists | timeout | text=XXXX | className=XXX.xxxx | resourceId=xxxxxx | """ if not self.d(**selectors).wait.exists(): raise AssertionError('UiObject does not exists %s' % selectors.items()) def result_should_be(self, expected): """Verifies that the current result is `expected`. Example: | Action | Argument | | Open application | com.android.settings/com.android.settings.Settings | | Result Should Be | 0 | """ print('result is: %s\n', self._result) print('ex is: %s\n', expected) if str(self._result) != expected: raise AssertionError('%s != %s' % (self._result, expected)) def click_at_coordinates(self, x, y): """ Click at (x,y) coordinates. Example: | Action | Argument | Argument | | Click At Corrdinates | x | y | """ return self.d.click(int(x), int(y)) def long_click_at_coordinates(self, x, y): """ # long click (x, y) on screen """ return self.d.long_click(int(x), int(y)) def swipe(self, sx, sy, ex, ey, steps=20): """ Swipe from (sx,sy) to (ex,ey) """ return self.d.swipe(int(sx), int(sy), int(ex), int(ex), int(steps)) def drag(self, sx, sy, ex, ey, steps=20): """ Drag from (sx,sy) to (ex,ey) """ return self.d.drag(int(sx), int(sy), int(ex), int(ex), int(steps)) def freeze_rotation(self, rotation=True): """ Freeze rotation, *rotation*, True is default, """ return self.d.freeze_rotation(rotation) def set_rotation(self, rotation): """ # retrieve orientation, # it should be "natural" or "left" or "right" or "upsidedown" Example: | Action | Argument | | Set Rotation | nature | | Set Rotation | left | | Set Rotation | right | | Set Rotation | upsidedown | """ orientation = self.d.orientation if rotation == "nature": self.d.orientation = "n" # or "natural" elif rotation == "left": self.d.orientation = "l" # or "left" elif rotation == "right": self.d.orientation = "r" # or "right" elif rotation == "upsidedown": self.d.orientation = "upsidedown" # or "upsidedown" else: self.d.rotation = "n" def take_screenshot(self, scale=None, quality=None): """ Take a screenshot of device and log in the report with timestamp, scale for screenshot size and quality for screenshot quality default scale=1.0 quality=100 Example: | Action | Argument | Argument | | Take Screenshot | 0.5 | 80 | """ output_dir = BuiltIn().get_variable_value('${OUTPUTDIR}') ts = time.time() st = datetime.datetime.fromtimestamp(ts).strftime('%Y%m%d%H%M%S') screenshot_path = '%s%s%s.png' % (output_dir, os.sep, st) screenshot_name = '%s%s.png' % (os.sep, st) self.d.screenshot(screenshot_path, scale, quality) logger.info('\n<a href="%s">%s</a><br><img src="%s">' % (screenshot_path, st, screenshot_name), html=True) def open_notification(self): """ Open notification of the phone """ self.d.open.notification() def wait_window_update(self): """ wait for window update """ return self.d.wait.update() def wait_window_idle(self): """ wait for window idle """ return self.d.wait.idle() def remove_watchers(self): """ Remove UI watchers """ self.d.watchers.remove() def get_device(self): """ Get device object, you can do any command using this """ return self.d def click_id(self, id, instance=0): """ Click *id* with *instance*=0 """ return self.d(resourceId=id, instance=instance).click.wait() def long_click_id(self, id, instance=0): """ Long click *id* with *instance*=0 """ return self.d(resourceId=id, instance=0).long_click() def click_description(self, description, instance=0): """ Click *description* with *instance*=0 """ return self.d(description=description, instance=instance).long_click() def click_class(self, className, instance=0): """ Click *className* with *instance*=0 """ return self.d(className=className, instance=instance).long_click() def type_text(self, textStr, **selectors): """ type text on selectors like text=EditName """ self.d(**selectors).set_text(textStr) def press_key(self, key): """ Press Key of following value home back left right up down center menu search enter delete(or del) recent(recent apps) volume_up volume_down volume_mute camera power Examples: | Action | Argument | | Press Key | home | | Press Key | back | | Press Key | left | | Press Key | right | | Press Key | recent | | Press Key | volume_up | | Press Key | camera | """ if key.isdigit(): return self.d.press(int(key)) return self.d.press(key) def phone_sleep(self, timeout): """ android device sleep with timeout in ms, don't use for executor sleep, """ return self.d.wait(int(timeout)) def execute_command(self, cmd, block_parent_process=True): """ Execute shell *cmd* command, with block_parent_process = True If block_parent_process = False, kill_command is needed to terminal the child process Example: | Execute Command | ping -c 5 127.0.0.1 | """ if str(block_parent_process) == str(True): return subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() else: return subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) def kill_command(self, process, timeout=0): """ Kill child *process* in timeout seconds Some bugs after process teminated """ time.sleep(float(timeout)) process.terminate() def wait_for_logcat(self, log, timeout=30): """ Wait log exists in given timeout, return True if have, otherwise will return False log is your want to search, log can be a regular expression time in seconds, default value is 30 seconds Example: | Wait For Logcat | .*ActivityManager.*cmp=com.sonyericsson.album/com.sonyericsson.album.Main.* | """ start = time.time() while (time.time() - start) < int(timeout): log_proc = self.adb.cmd("logcat -d -v time") returncode = log_proc.poll() lines = log_proc.stdout.readlines() for line in lines: rlt = re.search(log, line.rstrip()) if rlt is not None: print rlt.group(0) self._result = True return True time.sleep(2) #sleep 2s to wait self._result = False return False def clear_logcat(self): """ Clear logcat, it's often used before you want to use *wait_for_logcat()* """ print "Clear logcat before test" return self.exe_adb_command("logcat -c") def click_object(self, obj): """ Click UiObject *obj* Exmaple: | ${result} | Get UI Object | text=XXX | className=xxxx | | Click Object | ${result} | """ obj.click() def click_ui(self, **selectors): """ Click selector click_selector(text="Home", resourceId = "android:id/title") for **selector, please refer *get_ui_object()* Selector supports below parameters. Refer to UiSelector java doc for detailed information. text, textContains, textMatches, textStartsWith className, classNameMatches description, descriptionContains, descriptionMatches, descriptionStartsWith checkable, checked, clickable, longClickable scrollable, enabled,focusable, focused, selected packageName, packageNameMatches resourceId, resourceIdMatches index, instance Operation for a UiObjects: click, clear_text, drag(obj).to(**selector), gesture, exists, set_text, long_click pinch.In(percent=100, steps=10), pinch.Out(percent=100, steps=100),.swipe.right(), .swipe.left(steps=10),.swipe("right", steps=20),.wait.gone(),.wait.exists() """ print "selectors:", selectors return self.d(**selectors).click() def get_ui_object(self, **selectors): """ Get UI object with *selectors* you can do anything on UiObject, like click(), long_click(),wait.exists(timeout) examples: get_ui_object(text="Home", resourceId = "android:id/title") Selector supports below parameters. Refer to UiSelector java doc for detailed information. text, textContains, textMatches, textStartsWith className, classNameMatches description, descriptionContains, descriptionMatches, descriptionStartsWith checkable, checked, clickable, longClickable scrollable, enabled,focusable, focused, selected packageName, packageNameMatches resourceId, resourceIdMatches index, instance Operation for a UiObjects: click, clear_text, drag(obj).to(**selector), gesture, exists, set_text, long_click pinch.In(percent=100, steps=10), pinch.Out(percent=100, steps=100),.swipe.right(), .swipe.left(steps=10),.swipe("right", steps=20),.wait.gone(),.wait.exists() Exmaple: | ${result} | Get UI Object | text=XXX | className=xxxx | """ self._result = self.d(**selectors) return self._result def wait_for_object_exists(self, obj, timeout=0): """ Wait for UiObject *obj* exists in *timeout*= 0 Example: | ${result} | Get UI Object | text=XXX | className=xxxx | | Wait For Object Exists | ${result} | timeout | """ self._result = obj.wait.exists(timeout=int(timeout)) return self._result def wait_for_ui_gone(self, timeout=0, **selectors): """ Wait for UiObject *obj* gone in *timeout*= 0 Example: | ${result} | Get UI Object | text=XXX | className=xxxx | | Wait For Object Gone | ${result} | timeout | """ self._result = self.d(**selectors).wait.gone(timeout=int(timeout)) return self._result def get_key_value(self, key, dictionary): """ Get key value of dictionary """ return dictionary(key) def get_tts(self, input_text, delete_file=False, **args): """ Get TTS voice mp3 from Google get_tts(input_text='tunnel snakes rule apparently', args = {'language':'en','output':'outputto.mp3'}) Robot Framework: Examples: | Action | Argument | Argument | Argument | Argument | | UiTestLib.Get TTS | Hello world | False | output=ooo.mp3 | language=en | """ print "Get text to speech: ", input_text downloaded = False if str(delete_file) == 'True': if os.path.exists(args['output']): os.remove(args['output']) if os.path.exists(args['output']): if os.path.getsize(args['output']) <= 0: os.remove(args['output']) if args['output'] is not None: if not os.path.exists(args['output']): print 'Generating mp3 file......', args['output'] downloaded = GoogleTTS.audio_extract(input_text, args) else: print 'Have same local file' downloaded = True if not downloaded: print "Downloaded TTS from Google failed, trying to download from local FTP..." mp3file = open(args['output'], 'w') mp3url = 'ftp://cnbjlx9548/atautomation/Test-Content/Croft/' + args[ 'output'] try: resp = urllib2.urlopen(mp3url, timeout=40) mp3file.write(resp.read()) time.sleep(.05) except Exception, e: print e return False mp3file.close() return True
class ModelInfo(): ''' classdocs ''' def __init__(self, deviceserial): ''' Constructor ''' #sndLog = CLS("test", "test") self.osType = sys.platform self.mstrInfo = {} #self.devSerials = self.instAdb.device_serial() self.mstrDevice = Device(deviceserial) self.mstrInfo = self.mstrDevice.info ''' DEVICE Infoamtions { u'displayRotation': 0, u'displaySizeDpY': 640, u'displaySizeDpX': 360, u'currentPackageName': u'com.android.launcher', u'productName': u'takju', u'displayWidth': 720, u'sdkInt': 18, u'displayHeight': 1184, u'naturalOrientation': True } ''' def getCurrntProductInfo(self): return self.mstrInfo def getProductNmae(self): return self.mstrInfo['productName'] def getCurrntPkg(self): return self.mstrInfo['currentPackageName'] def getSDKInt(self): return self.mstrInfo['sdkInt'] def getRotation(self): return self.mstrInfo['displayRotation'] def getNaturalOri(self): return self.mstrInfo['naturalOrientation'] def getDisplayState(self): return self.mstrDevice.screen def setReflash(self): pass #define Key activity def setDevScrnOn(self): self.mstrDevice.screen.on() def setMstDevScrnOff(self): self.mstrDevice.screen.off() def setWakeup(self): self.mstrDevice.wakeup() def setSleep(self): self.mstrDevice.sleep() #Hard key Soft key def pressHome(self): return self.mstrDevice.press.home() def pressBack(self): return self.mstrDevice.press.back() ###################################################################### def pressLeft(self): return self.mstrDevice.press.left() def pressRight(self): return self.mstrDevice.press.right() def pressUp(self): return self.mstrDevice.press.up() def pressDown(self): return self.mstrDevice.press.down() def pressCenter(self): return self.mstrDevice.press.center() ###################################################################### def pressMenu(self): return self.mstrDevice.press.menu() def pressSearch(self): return self.mstrDevice.press.search() def pressEnter(self): return self.mstrDevice.press.enter() def pressDelete(self): return self.mstrDevice.press.delete() # or del def pressRecent(self): return self.mstrDevice.press.recent() def pressVol_Up(self): return self.mstrDevice.press.volume_up() def pressVol_Down(self): return self.mstrDevice.press.volume_down() def pressVol_Mute(self): return self.mstrDevice.press.volume_mute() def pressPower(self): return self.mstrDevice.press.power() def clik(self, x, y): return self.mstrDevice.click(x, y) def longClik(self,x, y): ''' Description: param: x, y : start first point x, y return : Boolean ''' return self.mstrDevice.long_click(x, y) def swipe(self, sx, sy, ex, ey, steps=10): ''' Description: param: sx, xy : start first x, y ex, ey : move to x, y return : Boolean ''' return self.mstrDevice.swipe(sx, sy, ex, ey, steps) def drage(self,sx, sy, ex, ey, steps=10): ''' Description: param: sx, xy : start first x, y ex, ey : move to x, y return : Boolean ''' return self.mstrDevice.drag(sx, sy, ex, ey, steps) #screen action of the device def setOrientation(self,scrAct='natural', choiceDevice='mstr'): ''' Description param d.orientation = 'l' or 'left' d.orientation = 'r' or 'right' d.orientation = 'n' or 'natural' return : None ''' self.mstrDevice.orientation = scrAct def setFreezeRotation(self,condition=False,choiceDevice='mstr'): ''' param: condition : False un-freeze rotation return : None ''' self.mstrDevice.freeze_rotation(condition) def takeScreenShot(self, choiceDevice = 'mstr'): ''' Description: take screenshot and save to local file 'home.png' can work until android 4.2 param image name ''' def dumpWindowHeirarchy(self,filename='./log/hierachy.xml'): return self.mstrDevice.dump(filename) def dumpWindowHeirarchyStream(self): return self.mstrDevice.dump() def notification(self): ''' Open notification, can not work until android 4.3 return : Boolean ''' return self.mstrDevice.open.Notification() def quickSettings(self): ''' open quick settins, can not work until android 4.3 return : Boolean ''' return self.mstrDevice.open.quick_settings() def waitidle(self): ''' wait for current window to idle return : None ''' self.mstrDevice.wait.idle() def waitWindowUpdate(self): ''' wait until window upate event occurs return : Boolean ''' self.mstrDevice.wait.update() def getCurrentActivityInfo(self, text): ''' INFOMATION: { u'contentDescription': u'', u'checked': False, u'scrollable': False, u'text': u'Settings', u'packageName': u'com.android.launcher', u'selected': False, u'enabled': True, u'bounds': {u'top': 385, u'right': 360, u'bottom': 585, u'left': 200}, u'className': u'android.widget.TextView', u'focused': False, u'focusable': True, u'clickable': True, u'chileCount': 0, u'longClickable': True, u'visibleBounds': {u'top': 385, u'right': 360, u'bottom': 585, u'left': 200}, u'checkable': False } ''' return self.mstrDevice(text).info def uiObjExist(self,text): ''' ture if exists, else False ''' return self.mstrDevice.exists(text) def watcher(self): pass def handler(self): pass def selector(self): pass def __del__(self): pass
class Mobile(): def __init__(self): self.set_serial(None) def set_serial(self, android_serial): """ Specify given *android_serial* device to perform test. You do not have to specify the device when there is only one device connects to the computer. When you need to use multiple devices, do not use this keyword to switch between devices in test execution. Using different library name when importing this library according to http://robotframework.googlecode.com/hg/doc/userguide/RobotFrameworkUserGuide.html?r=2.8.5. | Setting | Value | Value | Value | | Library | Mobile | WITH NAME | Mobile1 | | Library | Mobile | WITH NAME | Mobile2 | And set the serial to each library. | Test Case | Action | Argument | | Multiple Devices | Mobile1.Set Serial | device_1's serial | | | Mobile2.Set Serial | device_2's serial | """ self.adb = ADB(android_serial) self.device = Device(android_serial) self.test_helper = TestHelper(self.adb) def get_device_info(self): """ Retrieve the device info. The keyword will return a dictionary. You can log the information by using the log dictionary keyword in build in Collections library(http://robotframework.googlecode.com/hg/doc/libraries/Collections.html?r=2.8.4). Example: | ${device_info} | Get Device Info | | Log Dictionary | ${device_info} | => Dictionary size is 9 and it contains following items:\n currentPackageName: com.android.keyguard\n displayHeight: 1776\n displayRotation: 0\n displaySizeDpX: 360\n displaySizeDpY: 640\n displayWidth: 1080\n naturalOrientation: True\n productName: hammerhead\n sdkInt: 19\n Or get specific information of the device by giving the key. | ${device_info} | Get Device Info | | | | ${product_name} | Get From Dictionary | ${device_info} | productName | => ${product_name} = hammerhead """ return self.device.info #Key Event Actions of the device """ Turn on/off screen """ def turn_on_screen(self): """ Turn on the screen. """ self.device.screen.on() def turn_off_screen(self): """ Turn off the screen. """ self.device.screen.off() """ Press hard/soft key """ def press_key(self, *keys): """ Press *key* keycode. You can find all keycode in http://developer.android.com/reference/android/view/KeyEvent.html """ #not tested self.device.press(*keys) def press_home(self): """ Press home key. """ self.device.press.home() def press_back(self): """ Press back key. """ self.device.press.back() def press_left(self): """ Press left key. """ self.device.pres.left() def press_right(self): """ Press right key. """ self.device.press.right() def press_up(self): """ Press up key. """ self.device.press.up() def press_down(self): """ Press down key. """ self.device.press.down() def press_center(self): """ Press center key. """ self.device.press.center() def press_menu(self): """ Press menu key. """ self.device.press.menu() def press_search(self): """ Press search key. """ self.device.press.search() def press_enter(self): """ Press enter key. """ self.device.press.enter() def press_delete(self): """ Press delete key. """ self.device.press.delete() def press_recent(self): """ Press recent key. """ self.device.press.recent() def press_volume_up(self): """ Press volume up key. """ self.device.press.volume_up() def press_volume_down(self): """ Press volume down key. """ self.device.press.volume_down() def press_camera(self): """ Press camera key. """ self.device.press.camera() def press_power(self): """ Press power key. """ self.device.press.power() #Gesture interaction of the device def click_at_coordinates(self, x, y): """ Click at (x,y) coordinates. """ self.device.click(int(x), int(y)) def swipe_by_coordinates(self, sx, sy, ex, ey, steps=10): """ Swipe from (sx, sy) to (ex, ey) with *steps* . Example: | Swipe By Coordinates | 540 | 1340 | 940 | 1340 | | # Swipe from (540, 1340) to (940, 100) with default steps 10 | | Swipe By Coordinates | 540 | 1340 | 940 | 1340 | 100 | # Swipe from (540, 1340) to (940, 100) with steps 100 | """ self.device.swipe(sx, sy, ex, ey, steps) # Swipe from the center of the ui object to its edge def swipe_left(self, steps=10, *args, **selectors): """ Swipe the UI object with *selectors* from center to left. Example: | Swipe Left | description=Home screen 3 | | # swipe the UI object left | | Swipe Left | 5 | description=Home screen 3 | # swipe the UI object left with steps=5 | See `introduction` for details about Identified UI object. """ self.device(**selectors).swipe.left(steps=steps) def swipe_right(self, steps=10, *args, **selectors): """ Swipe the UI object with *selectors* from center to right See `Swipe Left` for more details. """ self.device(**selectors).swipe.right(steps=steps) def swipe_top(self, steps=10, *args, **selectors): """ Swipe the UI object with *selectors* from center to top See `Swipe Left` for more details. """ self.device(**selectors).swipe.up(steps=steps) def swipe_bottom(self, steps=10, *args, **selectors): """ Swipe the UI object with *selectors* from center to bottom See `Swipe Left` for more details. """ self.device(**selectors).swipe.down(steps=steps) def object_swipe_left(self, obj, steps=10): """ Swipe the *obj* from center to left Example: | ${object} | Get Object | description=Home screen 3 | # Get the UI object | | Object Swipe Left | ${object} | | # Swipe the UI object left | | Object Swipe Left | ${object} | 5 | # Swipe the UI object left with steps=5 | | Object Swipe Left | ${object} | steps=5 | # Swipe the UI object left with steps=5 | See `introduction` for details about identified UI object. """ obj.swipe.left(steps=steps) def object_swipe_right(self, obj, steps=10): """ Swipe the *obj* from center to right See `Object Swipe Left` for more details. """ obj.swipe.right(steps=steps) def object_swipe_top(self, obj, steps=10): """ Swipe the *obj* from center to top See `Object Swipe Left` for more details. """ obj.swipe.up(steps=steps) def object_swipe_bottom(self, obj, steps=10): """ Swipe the *obj* from center to bottom See `Object Swipe Left` for more details. """ obj.swipe.down(steps=steps) def drag_by_coordinates(self, sx, sy, ex, ey, steps=10): """ Drag from (sx, sy) to (ex, ey) with steps See `Swipe By Coordinates` also. """ self.device.drag(sx, sy, ex, ey, steps) #Wait until the specific ui object appears or gone # wait until the ui object appears def wait_for_exists(self, timeout=0, *args, **selectors): """ Wait for the object which has *selectors* within the given timeout. Return true if the object *appear* in the given timeout. Else return false. """ return self.device(**selectors).wait.exists(timeout=timeout) # wait until the ui object gone def wait_until_gone(self, timeout=0, *args, **selectors): """ Wait for the object which has *selectors* within the given timeout. Return true if the object *disappear* in the given timeout. Else return false. """ return self.device(**selectors).wait.gone(timeout=timeout) def wait_for_object_exists(self, obj, timeout=0): """ Wait for the object: obj within the given timeout. Return true if the object *appear* in the given timeout. Else return false. """ return obj.wait.exists(timeout=timeout) # wait until the ui object gone def wait_until_object_gone(self, obj, timeout=0): """ Wait for the object: obj within the given timeout. Return true if the object *disappear* in the given timeout. Else return false. """ return obj.wait.gone(timeout=timeout) # Perform fling on the specific ui object(scrollable) def fling_forward_horizontally(self, *args, **selectors): """ Perform fling forward (horizontally)action on the object which has *selectors* attributes. Return whether the object can be fling or not. """ return self.device(**selectors).fling.horiz.forward() def fling_backward_horizontally(self, *args, **selectors): """ Perform fling backward (horizontally)action on the object which has *selectors* attributes. Return whether the object can be fling or not. """ return self.device(**selectors).fling.horiz.backward() def fling_forward_vertically(self, *args, **selectors): """ Perform fling forward (vertically)action on the object which has *selectors* attributes. Return whether the object can be fling or not. """ return self.device(**selectors).fling.vert.forward() def fling_backward_vertically(self, *args, **selectors): """ Perform fling backward (vertically)action on the object which has *selectors* attributes. Return whether the object can be fling or not. """ return self.device(**selectors).fling.vert.backward() # Perform scroll on the specific ui object(scrollable) # horizontal def scroll_to_beginning_horizontally(self, steps=10, *args, **selectors): """ Scroll the object which has *selectors* attributes to *beginning* horizontally. See `Scroll Forward Vertically` for more details. """ return self.device(**selectors).scroll.horiz.toBeginning(steps=steps) def scroll_to_end_horizontally(self, steps=10, *args, **selectors): """ Scroll the object which has *selectors* attributes to *end* horizontally. See `Scroll Forward Vertically` for more details. """ return self.device(**selectors).scroll.horiz.toEnd(steps=steps) def scroll_forward_horizontally(self, steps=10, *args, **selectors): """ Perform scroll forward (horizontally)action on the object which has *selectors* attributes. Return whether the object can be Scroll or not. See `Scroll Forward Vertically` for more details. """ return self.device(**selectors).scroll.horiz.forward(steps=steps) def scroll_backward_horizontally(self, steps=10, *args, **selectors): """ Perform scroll backward (horizontally)action on the object which has *selectors* attributes. Return whether the object can be Scroll or not. See `Scroll Forward Vertically` for more details. """ return self.device(**selectors).scroll.horiz.backward(steps=steps) def scroll_to_horizontally(self, obj, *args, **selectors): """ Scroll(horizontally) on the object: obj to specific UI object which has *selectors* attributes appears. Return true if the UI object, else return false. See `Scroll To Vertically` for more details. """ return obj.scroll.horiz.to(**selectors) # vertical def scroll_to_beginning_vertically(self, steps=10, *args, **selectors): """ Scroll the object which has *selectors* attributes to *beginning* vertically. See `Scroll Forward Vertically` for more details. """ return self.device(**selectors).scroll.vert.toBeginning(steps=steps) def scroll_to_end_vertically(self, steps=10, *args, **selectors): """ Scroll the object which has *selectors* attributes to *end* vertically. See `Scroll Forward Vertically` for more details. """ return self.device(**selectors).scroll.vert.toEnd(steps=steps) def scroll_forward_vertically(self, steps=10, *args, **selectors): """ Perform scroll forward (vertically)action on the object which has *selectors* attributes. Return whether the object can be Scroll or not. Example: | ${can_be_scroll} | Scroll Forward Vertically | className=android.widget.ListView | | # Scroll forward the UI object with class name | | ${can_be_scroll} | Scroll Forward Vertically | 100 | className=android.widget.ListView | # Scroll with steps | """ return self.device(**selectors).scroll.vert.forward(steps=steps) def scroll_backward_vertically(self, steps=10, *args, **selectors): """ Perform scroll backward (vertically)action on the object which has *selectors* attributes. Return whether the object can be Scroll or not. See `Scroll Forward Vertically` for more details. """ return self.device(**selectors).scroll.vert.backward(steps=steps) def scroll_to_vertically(self, obj, *args, **selectors): """ Scroll(vertically) on the object: obj to specific UI object which has *selectors* attributes appears. Return true if the UI object, else return false. Example: | ${list} | Get Object | className=android.widget.ListView | | # Get the list object | | ${is_web_view} | Scroll To Vertically | ${list} | text=WebView | # Scroll to text:WebView. | """ return obj.scroll.vert.to(**selectors) #Screen Actions of the device def get_screen_orientation(self): """ Get the screen orientation. Possible result: natural, left, right, upsidedown See for more details: https://github.com/xiaocong/uiautomator#screen-actions-of-the-device """ return self.device.orientation def set_screen_orientation(self, orientation): """ Set the screen orientation. Input *orientation* : natural or n, left or l, right or r, upsidedown (support android version above 4.3) The keyword will unfreeze the screen rotation first. See for more details: https://github.com/xiaocong/uiautomator#screen-actions-of-the-device Example: | Set Screen Orientation | n | # Set orientation to natural | | Set Screen Orientation | natural | # Do the same thing | """ self.device.orientation = orientation def freeze_screen_rotation(self): """ Freeze the screen auto rotation """ self.device.freeze_rotation() def unfreeze_screen_rotation(self): """ Un-Freeze the screen auto rotation """ self.device.freeze_rotation(False) def screenshot(self, scale=None, quality=None): """ Take a screenshot of device and log in the report with timestamp, scale for screenshot size and quality for screenshot quality default scale=1.0 quality=100 """ output_dir = BuiltIn().get_variable_value('${OUTPUTDIR}') ts = time.time() st = datetime.datetime.fromtimestamp(ts).strftime('%Y%m%d%H%M%S') screenshot_path = '%s%s%s.png' % (output_dir, os.sep, st) self.device.screenshot(screenshot_path, scale, quality) logger.info('\n<a href="%s">%s</a><br><img src="%s">' % (screenshot_path, st, screenshot_path), html=True) #Watcher def __unicode_to_dict(self, a_unicode): a_dict = dict() dict_item_count = a_unicode.count('=') for count in range(dict_item_count): equal_sign_position = a_unicode.find('=') comma_position = a_unicode.find(',') a_key = a_unicode[0:equal_sign_position] if comma_position == -1: a_value = a_unicode[equal_sign_position + 1:] else: a_value = a_unicode[equal_sign_position + 1:comma_position] a_unicode = a_unicode[comma_position + 1:] a_dict[a_key] = a_value return a_dict def register_click_watcher(self, watcher_name, selectors, *condition_list): """ The watcher click on the object which has the *selectors* when conditions match. """ watcher = self.device.watcher(watcher_name) for condition in condition_list: watcher.when(**self.__unicode_to_dict(condition)) watcher.click(**self.__unicode_to_dict(selectors)) self.device.watchers.run() def register_press_watcher(self, watcher_name, press_keys, *condition_list): """ The watcher perform *press_keys* action sequentially when conditions match. """ def unicode_to_list(a_unicode): a_list = list() comma_count = a_unicode.count(',') for count in range(comma_count + 1): comma_position = a_unicode.find(',') if comma_position == -1: a_list.append(str(a_unicode)) else: a_list.append(a_unicode[0:comma_position]) a_unicode = a_unicode[comma_position + 1:] return a_list watcher = self.device.watcher(watcher_name) for condition in condition_list: watcher.when(**self.__unicode_to_dict(condition)) watcher.press(*unicode_to_list(press_keys)) self.device.watchers.run() def remove_watchers(self, watcher_name=None): """ Remove watcher with *watcher_name* or remove all watchers. """ if watcher_name == None: self.device.watchers.remove() else: self.device.watchers.remove(watcher_name) def list_all_watchers(self): """ Return the watcher list. """ return self.device.watchers #Selector def get_object(self, *args, **selectors): """ Get the UI object with selectors *selectors* See `introduction` for details about identified UI object. Example: | ${main_layer} | Get Object | className=android.widget.FrameLayout | index=0 | # Get main layer which class name is FrameLayout | """ return self.device(*args, **selectors) def get_child(self, object, *args, **selectors): """ Get the child or grandchild UI object from the *object* with *selectors* Example: | ${root_layout} | Get Object | className=android.widget.FrameLayout | | ${child_layout} | Get Child | ${root_layout} | className=LinearLayout | """ return object.child(*args, **selectors) def get_sibling(self, object, *args, **selectors): """ Get the sibling or child of sibling UI object from the *object* with *selectors* Example: | ${root_layout} | Get Object | className=android.widget.FrameLayout | | ${sibling_layout} | Get Sibling | ${root_layout} | className=LinearLayout | """ return object.sibling(*args, **selectors) def get_count(self, *args, **selectors): """ Return the count of UI object with *selectors* Example: | ${count} | Get Count | text=Accessibility | # Get the count of UI object text=Accessibility | | ${accessibility_text} | Get Object | text=Accessibility | # These two keywords combination | | ${count} | Get Count Of Object | ${accessibility_text} | # do the same thing. | """ obj = self.get_object(**selectors) return self.get_count_of_object(obj) # def get_count_of_object(self, obj): # """ # Return the count of given UI object # # See `Get Count` for more details. # """ # return len(obj) def get_info_of_object(self, obj, selector=None): """ return info dictionary of the *obj* The info example: { u'contentDescription': u'', u'checked': False, u'scrollable': True, u'text': u'', u'packageName': u'com.android.launcher', u'selected': False, u'enabled': True, u'bounds': { u'top': 231, u'left': 0, u'right': 1080, u'bottom': 1776 }, u'className': u'android.view.View', u'focusable': False, u'focused': False, u'clickable': False, u'checkable': False, u'chileCount': 1, u'longClickable': False, u'visibleBounds': { u'top': 231, u'left': 0, u'right': 1080, u'bottom': 1776 } } """ if selector: return obj.info.get(selector) else: return obj.info def click(self, *args, **selectors): """ Click on the UI object with *selectors* | Click | text=Accessibility | className=android.widget.Button | # Click the object with class name and text | """ self.device(**selectors).click() def click_on_object(self, object): """ Click on the UI object which is gained by `Get Object`. Example: | ${button_ok} | text=OK | className=android.widget.Button | | Click on Object | ${button_ok} | """ return object.click() def long_click(self, *args, **selectors): """ Long click on the UI object with *selectors* See `Click` for more details. """ self.device(**selectors).long_click() def call(self, obj, method, *args, **selectors): """ This keyword can use object method from original python uiautomator See more details from https://github.com/xiaocong/uiautomator Example: | ${accessibility_text} | Get Object | text=Accessibility | # Get the UI object | | Call | ${accessibility_text} | click | # Call the method of the UI object 'click' | """ func = getattr(obj, method) return func(**selectors) def set_text(self, input_text, *args, **selectors): """ Set *input_text* to the UI object with *selectors* """ self.device(**selectors).set_text(input_text) def set_object_text(self, input_text, object): """ Set *input_text* the *object* which could be selected by *Get Object* or *Get Child* """ object.set_text(input_text) # Other feature def clear_text(self, *args, **selectors): """ Clear text of the UI object with *selectors* """ while True: target = self.device(**selectors) text = target.info['text'] target.clear_text() remain_text = target.info['text'] if text == '' or remain_text == text: break def open_notification(self): """ Open notification Built in support for Android 4.3 (API level 18) Using swipe action as a workaround for API level lower than 18 """ sdk_version = self.device.info['sdkInt'] if sdk_version < 18: height = self.device.info['displayHeight'] self.device.swipe(1, 1, 1, height - 1, 1) else: self.device.open.notification() def open_quick_settings(self): """ Open quick settings Work for Android 4.3 above (API level 18) """ self.device.open.quick_settings() def sleep(self, time): """ Sleep(no action) for *time* (in millisecond) """ target = 'wait for %s' % str(time) self.device(text=target).wait.exists(timeout=time) def install(self, apk_path): """ Install apk to the device. Example: | Install | ${CURDIR}${/}com.hmh.api_4.0.apk | # Given the absolute path to the apk file | """ self.adb.cmd('install "%s"' % apk_path) def uninstall(self, package_name): """ Uninstall the APP with *package_name* """ self.adb.cmd('uninstall %s' % package_name) def execute_adb_command(self, cmd): """ Execute adb *cmd* """ return self.adb.cmd(cmd) def execute_adb_shell_command(self, cmd): """ Execute adb shell *cmd* """ return self.adb.shell_cmd(cmd) def type(self, input_text): """ [IME] Type *text* at current focused UI object """ self.test_helper.send_set_text_cmd(input_text) def start_test_agent(self): """ [Test Agent] Start Test Agent Service """ cmd = 'am start edu.ntut.csie.sslab1321.testagent/edu.ntut.csie.sslab1321.testagent.DummyActivity' self.adb.shell_cmd(cmd) def stop_test_agent(self): """ [Test Agent] Stop Test Agent Service """ cmd = 'am broadcast -a testagent -e action STOP_TESTAGENT' self.adb.shell_cmd(cmd) def connect_to_wifi(self, ssid, password=None): """ [Test Agent] Connect to *ssid* with *password* """ cmd = 'am broadcast -a testagent -e action CONNECT_TO_WIFI -e ssid %s -e password %s' % ( ssid, password) self.adb.shell_cmd(cmd) def clear_connected_wifi(self): """ [Test Agent] Clear all existed Wi-Fi connection """ cmd = 'am broadcast -a testagent -e action CLEAR_CONNECTED_WIFIS' self.adb.shell_cmd(cmd)
class AndroidDevice(object): ''' wrapper for android uiautomator(pip install uiautomator) and image comparision(pip install imglib) to provide android device event inject and ui object inspect and image comparison. ''' def __init__(self): self.serial = configer.env[ANDROID_SERIAL] if configer.env.has_key(ANDROID_SERIAL) else None self.d = Device(self.serial) def __getattr__(self, method): ''' forward method to uiautomator device if method support by uiautomator. ''' if hasattr(self.d, method): def wrapper(*args, **kwargs): return getattr(self.d, method)(*args, **kwargs) return wrapper raise AttributeError(method) def serial(self): '''device serial number from $ANDROID_SERIAL ''' return self.serial def info(self): '''retrieve the device info''' return self.d.info def sleep(self, seconds): time.sleep(seconds) return self #device event inject def start_activity(self, **kwargs): '''launch application from android shell am start: component, flag // from adb docs: //<INTENT> specifications include these flags: // [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>] // [-c <CATEGORY> [-c <CATEGORY>] ...] // [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...] // [--esn <EXTRA_KEY> ...] // [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...] // [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...] // [-n <COMPONENT>] [-f <FLAGS>] // [<URI>] ''' #d.server.adb.cmd('shell','am', 'start', '-a', 'android.intent.action.DIAL','tel:13581739891').communicate() #sys.stderr.write(str(kwargs)) keys = kwargs.keys() shellcmd = ['shell', 'am', 'start'] if 'component' in keys: shellcmd.append('-n') shellcmd.append(kwargs['component']) if 'action' in keys: shellcmd.append('-a') shellcmd.append(kwargs['action']) if 'data' in keys: shellcmd.append('-d') shellcmd.append(kwargs['data']) if 'mimetype' in keys: shellcmd.append('-t') shellcmd.append(kwargs['mimetype']) if 'categories' in keys: for category in kwargs['categories']: shellcmd.append('-c') shellcmd.append(category) if 'extras' in keys: for extra_key, extra_value in kwargs['extras'].items(): str_value = '' arg = '' if isinstance(extra_value, types.IntType): str_value = str(extra_value) arg = '--ei' elif isinstance(extra_value, types.BooleanType): str_value = str(extra_value) arg = '--ez' else: str_value = str(extra_value) arg = '--es' shellcmd.append(arg) shellcmd.append(extra_key) shellcmd.append(str_value) if 'flags' in keys: shellcmd.append('-f') shellcmd.append(str(kwargs['flags'])) if 'uri' in keys: shellcmd.append(kwargs['uri']) #sys.stderr.write(str(shellcmd)) self.d.server.adb.cmd(*shellcmd).communicate() return self def instrument(self, **kwargs): keys = kwargs.keys() shellcmd = ['shell', 'am', 'instrument', '-w', '-r'] pkgname = kwargs.pop('packagename') for k, v in kwargs.items(): if k and v: shellcmd.append('-e') shellcmd.append(k) shellcmd.append(str(v)) shellcmd.append(pkgname) result = self.d.server.adb.cmd(*shellcmd).communicate() return result def TODOinstallPackage(self, **kwargs): pass def TODOremovePackage(self, **kwargs): pass def press(self, keyname, waittime=1): #hard, soft key: home,back,up,down,right,left,center,menu,power or ANDROID_KEYEVENT self.d.press(keyname) time.sleep(waittime) return self def click(self, x, y, waittime=1): self.d.click(x, y) time.sleep(waittime) return self def click_image(self, imagename, waittime=1, threshold=0.01): ''' if the wanted image found on current screen click it. if the wanted image not found raise exception and set test to be failure. ''' expect_image_path = os.path.join(configer['right_dir_path'], imagename) assert os.path.exists(expect_image_path), 'the local expected image %s not found!' % imagename current_image_path = os.path.join(configer['report_dir_path'], imagename) self.d.screenshot(current_image_path) assert os.path.exists(current_image_path), 'fetch current screen shot image %s failed!' % imagename pos = getMatchedCenterOffset(expect_image_path, current_image_path, threshold) assert pos, 'Fail Reason: The wanted image \'%s\' not found on screen!' % imagename self.d.click(pos[0], pos[1]) time.sleep(waittime) return self def swipe(self, sx, sy, ex, ey, steps=100, waittime=1): self.d.swipe(sx, sy, ex, ey, steps) time.sleep(waittime) return self def drag(self, sx, sy, ex, ey, steps=100, waittime=1): self.d.drag(sx, sy, ex, ey, steps) time.sleep(waittime) return self #inspect def exists(self, **kwargs): ''' if the expected component exists on current screen layout return true else return false. ''' return self.d.exists(**kwargs) #device snapshot def screenshot(self, filename, waittime=1): path = os.path.join(configer['report_dir_path'], filename) self.d.screenshot(path) return self def expect(self, imagename, interval=2, timeout=4, threshold=0.01, msg=''): ''' if the expected image found on current screen return self else raise exception. set test to be failure. ''' expect_image_path = os.path.join(configer['right_dir_path'], imagename) assert os.path.exists(expect_image_path) current_image_path = os.path.join(configer['report_dir_path'], imagename) begin = time.time() while (time.time() - begin < timeout): self.d.screenshot(current_image_path) if isMatch(expect_image_path , current_image_path , threshold): return self time.sleep(interval) name, ext = os.path.splitext(os.path.basename(imagename)) shutil.copyfile(expect_image_path, os.path.join(configer['report_dir_path'], '%s%s%s' % (name, '_expect', ext))) reason = msg if not msg else 'Fail Reason: Image \'%s\' not found on screen!' % imagename assert False, reason def find(self, imagename, interval=2, timeout=4, threshold=0.01): ''' if the expected image found on current screen return true else return false ''' expect_image_path = os.path.join(configer['right_dir_path'], imagename) assert os.path.exists(expect_image_path) current_image_path = os.path.join(configer['report_dir_path'], imagename) begin = time.time() isExists = False while (time.time() - begin < timeout): time.sleep(interval) self.d.screenshot(current_image_path) isExists = isMatch(expect_image_path , current_image_path , threshold) if not isExists: time.sleep(interval) continue return isExists
class uiAutomatorLib: def __init__(self): self.device = None def getDeviceInstance(self,deviceId): #deviceId = self.getDeviceID() #if deviceId is not None: #self.device = Device(deviceId) self.device = Device(deviceId) def getDeviceID(self): deviceId = None cmd = "devices" output = self.executeCommandOnDevice(cmd) if output is not None: reObj = re.search(r'(\w+-?\w+?).*device\b', output,re.MULTILINE) if reObj: deviceId = reObj.group(1).strip() return deviceId else: return "No Device" def openAppList(self): self.device.press.home() self.swipeUp() def getCoOrdinates(self, xPercentage, yPercentage): x = (self.device.info['displayWidth'] * xPercentage) / 100 y = (self.device.info['displayHeight'] * yPercentage) / 100 return x, y def swipeUp(self): x1, y1 = self.getCoOrdinates(50, 75) x2, y2 = self.getCoOrdinates(50, 25) self.device.swipe(x1, y1, x2, y2) def swipeDown(self): x1, y1 = self.getCoOrdinates(50, 25) x2, y2 = self.getCoOrdinates(50, 75) self.device.swipe(x1, y1, x2, y2) def scrollUp(self, speed=60): x1, y1 = self.getCoOrdinates(50, 75) x2, y2 = self.getCoOrdinates(50, 25) cmd = "shell input touchscreen swipe {} {} {} {} {}".format(x1, y1, x2, y2, speed) self.executeCommandOnDevice(cmd) def scrollDown(self, speed=60): x1, y1 = self.getCoOrdinates(50, 25) x2, y2 = self.getCoOrdinates(50, 75) cmd = "shell input touchscreen swipe {} {} {} {} {}".format(x1, y1, x2, y2, speed) self.executeCommandOnDevice(cmd) def scrollRight(self, speed=60): x1, y1 = self.getCoOrdinates(25, 50) x2, y2 = self.getCoOrdinates(75, 50) cmd = "shell input touchscreen swipe {} {} {} {} {}".format(x1, y1, x2, y2, speed) self.executeCommandOnDevice(cmd) def scrollLeft(self, speed=60): x1, y1 = self.getCoOrdinates(75, 50) x2, y2 = self.getCoOrdinates(25, 50) cmd = "shell input touchscreen swipe {} {} {} {} {}".format(x1, y1, x2, y2, speed) self.executeCommandOnDevice(cmd) def dragUp(self): x1, y1 = self.getCoOrdinates(50, 75) x2, y2 = self.getCoOrdinates(50, 25) self.device.drag(x1, y1, x2, y2) def dragDown(self): x1, y1 = self.getCoOrdinates(50, 25) x2, y2 = self.getCoOrdinates(50, 75) self.device.drag(x1, y1, x2, y2) def clickUsingText(self, textObj, className=None, instance=0): if className is not None: self.device(text=textObj, className=className, instance=instance).click.wait() else: self.device(text=textObj, instance=instance).click.wait() sleep(1) def clickUsingDescription(self, textObj, className=None, instance=0): if className is None: self.device(description=textObj, instance=instance).click.wait() sleep(1) else: self.device(description=textObj, className=className, instance=instance).click.wait() def clearText(self, textObj, instance=0): self.device(text=textObj, instance=instance).clear_text() def setText(self, textObj, text, instance=0): self.device(text=textObj, instance=instance).set_text(text) sleep(1) def pressDown(self): self.device.press.down() sleep(1) def pressEnter(self): self.device.press.enter() sleep(1) def pressBack(self): self.device.press.back() def scrollAndClickAnElement(self, textObj, className=None, instance=0): count = 0 while count <= 20: if self.isElementwithTextExists(textObj): self.clickUsingText(textObj, className, instance) break else: self.scrollUp(500) def isElementwithTextExists(self, textObj): if self.device(text=textObj).exists: return True return False def checkAndClickUsingText(self, textObj, className=None, instance=0): counter = 0 while counter <= 5: if self.isElementwithTextExists(textObj): self.clickUsingText(textObj, className, instance) sleep(2) break else: sleep(1) counter += 1 return False def pullFiles(self, source, destination): cmd = "pull {} {}".format(source, destination) self.executeCommandOnDevice(cmd) def enterText(self, text): cmd = "shell input text {}".format(text) self.executeCommandOnDevice(cmd) def pressKeycode(self, keycode): cmd = "shell input keyevent {}".format(keycode) self.executeCommandOnDevice(cmd) def isElementExistsWithDescription(self, descriptionObj): if self.device(description=descriptionObj).exists: return True return False def clickUsingDescription(self, descriptionObj, className=None, instance=0): if className is None: self.device(text=descriptionObj, instance=instance).click.wait() sleep(1) else: self.device(text=descriptionObj, className=className, instance=instance).click.wait() def checkAndClickUsingDescription(self, descriptionObj, instance=0): counter = 0 while counter <= 5: if self.isElementExistsWithDescription(descriptionObj): self.clickUsingDescription(descriptionObj, instance) sleep(2) break else: sleep(1) counter += 1 return False def isElementExistsWithResourceId(self, resourceIdObj): if self.device(resourceId=resourceIdObj).exists: return True return False def waituntillgettingresourceId(self,resourceIdObj,time): if self.device(resourceId=resourceIdObj).wait.exists(timeout=int(time)): return True return False def clickUsingResourceId(self, resourceIdObj, className=None, instance=0): if className is None: self.device(resourceId=resourceIdObj, instance=instance).click.wait() sleep(1) else: self.device(resourceId=resourceIdObj, className=className, instance=instance).click.wait() def checkAndClickUsingResourceId(self, resourceIdObj, instance=0): counter = 0 while counter <= 5: if self.isElementExistsWithResourceId(resourceIdObj): self.clickUsingResourceId(resourceIdObj, instance) sleep(2) break else: sleep(1) counter += 1 return False def getDeviceProperty(self, property): ''' It will give the property of the device :param property: :return: ''' try: cmd = "shell getprop" output = self.executeCommandOnDevice(cmd) if output is not None: lines = output.splitlines() for line in lines: if property in line: (key, value) = line.split(':') patternObj = re.search(r'\[(.*)\]', value) if patternObj: return patternObj.group(1) else: print("property is not found in getprop list") return None except Exception as e: print("Error:Unable to get the device property") print(e.__str__()) def getDeviceBrand(self): ''' It will return the brand of the device(Ex: Samsung,onePlus..etc) :return: ''' brand = self.getDeviceProperty('ro.product.brand') return brand def getDeviceModel(self): ''' It will return the model of the device :return: ''' model = self.getDeviceProperty('ro.product.model') return model def getInstalledApps(self): ''' It will return the list of applications installed on the device :return: ''' cmd = "shell pm list packages" packageList = self.executeCommandOnDevice(cmd) if packageList is not None: return packageList def isApplicationInstalled(self, packageName): ''' It checks whether the given application is installed on the device or not :param packageName: :return: Boolean ''' try: packageList = self.getInstalledApps() if packageList is not None: packageLines = packageList.splitlines() for line in packageLines: if packageName in line: patternObj = re.search(r'package:(.*)', line) if patternObj: pkgName = patternObj.group(1) if pkgName == packageName: return True return False except Exception as e: print("Error: while checking the application status") print(e.__str__()) def recordScreen(self, filePath): ''' It will record the screen whatever actions we performed on the device :param filePath: :return: ''' cmd = "shell screenrecord {}".format(filePath) return self.executeCommandInBackground(cmd) def setScreenTimeOut(self, time=600000): ''' It will set the device display timeout :param time: :return: ''' cmd = "shell settings put system screen_off_timeout {}".format(time) self.executeCommandOnDevice(cmd) def isDisplayON(self): try: cmd = "shell dumpsys display" output = self.executeCommandOnDevice(cmd) if output is not None: lines = output.splitlines() for line in lines: if 'mScreenState' in line: (key, value) = line.split('=') if value == "ON": return True else: return False except Exception as e: print("Error while checking the display status") print(e.__str__()) def turnDisplayON(self): ''' It will turn on the display :return: ''' cmd = "shell input keyevent 26" self.executeCommandOnDevice(cmd) def getText(self, resourceObj, className): ''' It will extract the value of the textbox and returns the text :return: string ''' info = self.device(resourceId=resourceObj, className=className).info return info['text'] def executeCommandOnDevice(self,command): try: output = None commandToExecute = self.__getPrefixCommand() commandToExecute += command output = subprocess.check_output(commandToExecute, shell=True) if output is not None: outputStr = output.decode('utf-8') return outputStr return None except Exception as e: print("Error: {}".format(e.__str__())) return None def __getPrefixCommand(self): return "adb " def executeCommandInBackground(self,command, fileHandle=None): try: output = None commandToExecute = self.__getPrefixCommand() commandToExecute += command pid = subprocess.Popen(commandToExecute,stdin=fileHandle,stdout=fileHandle,shell=False) if pid is not None: return pid return None except Exception as e: print("Error: {}".format(e.__str__())) return None def executeCommand(self,cmd): try: output = subprocess.check_output(cmd) if output is not None: outputStr = output.decode('utf-8') return outputStr return None except Exception as e: print("Error: {}".format(e.__str__())) return None def turn_on_off_wifi(self,deviceID,wifi_mode): command = 'adb -s '+str(deviceID)+' shell svc wifi enable' if wifi_mode=='off': command = 'adb -s '+str(deviceID)+' shell svc wifi disable' self.executeCommand(command) def executeCommandAndWriteToFile(self, cmd, filePath): pid = None try: with open(filePath, 'w') as f: pid = self.executeCommandInBackground(cmd, f) except Exception as e: print("Exception occured while collecting logcat") print(e.__str__) finally: return pid def collectLogcat(self, filePath): cmd = "logcat" pid = self.executeCommandAndWriteToFile(cmd, filePath) return pid def launch_Application_using_adb(self, packageName, activityName,deviceID): try: cmd = "-s "+str(deviceID) +" shell am start -n {}/{}".format(packageName, activityName) self.executeCommandOnDevice(cmd) except Exception as e: print("Exception occured while launching an application:{}".format(packageName)) print(e.__str__()) def close_application_using_adb(self, packageName,deviceID): try: cmd = "-s "+str(deviceID) +" shell am force-stop {}".format(packageName) self.executeCommandOnDevice(cmd) except Exception as e: print("Exception occured while Closing an application:{}".format(packageName)) print(e.__str__()) def make_call_using_adb(self,number,deviceID): try: cmd = "-s "+str(deviceID) +' shell am start -a android.intent.action.CALL -d tel:"'+str(number)+'"' self.executeCommandOnDevice(cmd) except Exception as e: print("Exception occured while calling a number:{}".format(number)) print(e.__str__()) def verify_call_connection(self,deviceID): try: cmd = "-s "+str(deviceID) +' shell dumpsys telephony.registry | grep mCallState' status = self.executeCommandOnDevice(cmd) status =int(status.split('mCallState=')[2]) if status!=0: return True else: return False except Exception as e: print("Exception occured while verifying a call connection") print(e.__str__()) def end_call_using_adb(self,deviceID): try: cmd = "-s "+str(deviceID) +' shell input keyevent 6' self.executeCommandOnDevice(cmd) except Exception as e: print("Exception occured while ending a call connection") print(e.__str__()) def verify_call_disconnection(self,deviceID): try: cmd = "-s "+str(deviceID) +' shell dumpsys telephony.registry | grep mCallState' status = self.executeCommandOnDevice(cmd) status =int(status.split('mCallState=')[2]) if status==0: return True else: return False except Exception as e: print("Exception occured while verifying a call disconnection") print(e.__str__()) def closeRecentApplication(self): self.pressKeycode("KEYCODE_APP_SWITCH") count = 0 while (count <= 5): if self.isElementwithTextExists('CLEAR ALL'): self.clickUsingText("CLEAR ALL") break else: self.scrollDown() count = count - 1 def reboot(self): self.executeCommandOnDevice('reboot') def root(self): self.executeCommandOnDevice('root') def remount(self): self.executeCommandOnDevice('remount') def launchApplication(self,packageName, activityName): cmd = "shell am start -W -n {}/{}".format(packageName,activityName) output = self.executeCommandOnDevice(cmd) return self.getAppLaunchTime(output) def getAppLaunchTime(self, outputStr): reg = re.search(r'.*TotalTime:\s+(\d+).*', outputStr, re.MULTILINE) launchTime = 0 if reg: launchTime = reg.group(1) return launchTime def deleteDeviceInstance(self): self.executeCommandOnDevice("kill-server") self.device = None del self def reboot_to_normal(self): self.reboot() total_time=0 while(total_time<100): print (total_time) device_id =self.getDeviceID() if device_id != "No Device": break total_time=total_time+5 print (device_id,total_time) sleep(5) if self.waituntillgettingresourceId('com.android.launcher3:id/workspace',65000): return True return False def sam(self): try: subprocess.call('dfsdf') except Exception as e: print("Exception occured while Closing an application:{}") print(e)
class Mobile(): def __init__(self): pass def set_serial(self, android_serial): """ Specify given *android_serial* device to perform test. You do not have to specify the device when there is only one device connects to the computer. When you need to use multiple devices, do not use this keyword to switch between devices in test execution. Using different library name when importing this library according to http://robotframework.googlecode.com/hg/doc/userguide/RobotFrameworkUserGuide.html?r=2.8.4#setting-custom-name-to-test-library. | ==Setting== | ==Value== | ==Value== | ==Value== | | Library | Mobile | WITH NAME | Mobile1 | | Library | Mobile | WITH NAME | Mobile2 | And set the serial to each library. | Test Case | Action | Argument | | Multiple Devices | Mobile1.Set Serial | device_1's serial | | | Mobile2.Set Serial | device_2's serial | """ self.adb = ADB(android_serial) self.device = Device(android_serial) self.test_helper = TestHelper(self.adb) def get_device_info(self): """ Retrieve the device info. The keyword will return a dictionary. You can log the information by using the log dictionary keyword in build in Collections library(http://robotframework.googlecode.com/hg/doc/libraries/Collections.html?r=2.8.4). Example: | ${device_info} | Get Device Info | | Log Dictionary | ${device_info} | => Dictionary size is 9 and it contains following items:\n currentPackageName: com.android.keyguard\n displayHeight: 1776\n displayRotation: 0\n displaySizeDpX: 360\n displaySizeDpY: 640\n displayWidth: 1080\n naturalOrientation: True\n productName: hammerhead\n sdkInt: 19\n Or get specific information of the device by giving the key. | ${device_info} | Get Device Info | | | | ${product_name} | Get From Dictionary | ${device_info} | productName | => ${product_name} = hammerhead """ return self.device.info #Key Event Actions of the device """ Turn on/off screen """ def turn_on_screen(self): """ Turn on screen """ self.device.screen.on() def turn_off_screen(self): """ Turn off screen """ self.device.screen.off() """ Press hard/soft key """ def press_key(self, *keys): """ Press *key* keycode. You can find all keycode in http://developer.android.com/reference/android/view/KeyEvent.html """ #not tested self.device.press(*keys) def press_home(self): """ Press home key """ self.device.press.home() def press_back(self): """ Press back key """ self.device.press.back() def press_left(self): """ Press left key """ self.device.pres.left() def press_right(self): """ Press right key """ self.device.press.right() def press_up(self): """ Press up key """ self.device.press.up() def press_down(self): """ Press down key """ self.device.press.down() def press_center(self): """ Press center key """ self.device.press.center() def press_menu(self): """ Press menu key """ self.device.press.menu() def press_search(self): """ Press search key """ self.device.press.search() def press_enter(self): """ Press enter key """ self.device.press.enter() def press_delete(self): """ Press delete key """ self.device.press.delete() def press_recent(self): """ Press recent key """ self.device.press.recent() def press_volume_up(self): """ Press volume up key """ self.device.press.volume_up() def press_volume_down(self): """ Press volume down key """ self.device.press.volume_down() def press_camera(self): """ Press camera key """ self.device.press.camera() def press_power(self): """ Press power key """ self.device.press.power() #Gesture interaction of the device def click_at_coordinates(self, x, y): """ Click at (x,y) coordinates. """ self.device.click(x, y) def swipe_by_coordinates(self, sx, sy, ex, ey, steps=10): """ Swipe from (sx, sy) to (ex, ey) with *steps* . Example: | Swipe By Coordinates | 540 | 1340 | 940 | 1340 | | # Swipe from (540, 1340) to (940, 100) with default steps 10 | | Swipe By Coordinates | 540 | 1340 | 940 | 1340 | 100 | # Swipe from (540, 1340) to (940, 100) with steps 100 | """ self.device.swipe(sx, sy, ex, ey, steps) # Swipe from the center of the ui object to its edge def swipe_left(self, steps=10, *args, **selectors): """ Swipe the UI object with *selectors* from center to left. Example: | Swipe Left | description=Home screen 3 | | # swipe the UI object left | | Swipe Left | 5 | description=Home screen 3 | # swipe the UI object left with steps=5 | See `introduction` for details about identified UI object. """ self.device(**selectors).swipe.left(steps=steps) def swipe_right(self, steps=10, *args, **selectors): """ Swipe the UI object with *selectors* from center to right See `Swipe Left` for more details. """ self.device(**selectors).swipe.right(steps=steps) def swipe_top(self, steps=10, *args, **selectors): """ Swipe the UI object with *selectors* from center to top See `Swipe Left` for more details. """ self.device(**selectors).swipe.up(steps=steps) def swipe_bottom(self, steps=10, *args, **selectors): """ Swipe the UI object with *selectors* from center to bottom See `Swipe Left` for more details. """ self.device(**selectors).swipe.down(steps=steps) def object_swipe_left(self, obj, steps=10): """ Swipe the *obj* from center to left Example: | ${object} | Get Object | description=Home screen 3 | # Get the UI object | | Object Swipe Left | ${object} | | # Swipe the UI object left | | Object Swipe Left | ${object} | 5 | # Swipe the UI object left with steps=5 | | Object Swipe Left | ${object} | steps=5 | # Swipe the UI object left with steps=5 | See `introduction` for details about identified UI object. """ obj.swipe.left(steps=steps) def object_swipe_right(self, obj, steps=10): """ Swipe the *obj* from center to right See `Object Swipe Left` for more details. """ obj.swipe.right(steps=steps) def object_swipe_top(self, obj, steps=10): """ Swipe the *obj* from center to top See `Object Swipe Left` for more details. """ obj.swipe.up(steps=steps) def object_swipe_bottom(self, obj, steps=10): """ Swipe the *obj* from center to bottom See `Object Swipe Left` for more details. """ obj.swipe.down(steps=steps) def drag_by_coordinates(self,sx, sy, ex, ey, steps=10): """ Drag from (sx, sy) to (ex, ey) with steps See `Swipe By Coordinates` also. """ self.device.drag(sx, sy, ex, ey, steps) #Wait until the specific ui object appears or gone # wait until the ui object appears def wait_for_exists(self, timeout=0, *args, **selectors): """ true means the object which has *selectors* exist false means the object does not exist in the given timeout """ return self.device(**selectors).wait.exists(timeout=timeout) # wait until the ui object gone def wait_until_gone(self, timeout=0, *args, **selectors): """ true means the object which has *selectors* disappear false means the object exist in the given timeout """ return self.device(**selectors).wait.gone(timeout=timeout) def wait_for_object_exists(self, obj, timeout=0): """ true means the object exist false means the object does not exist in the given timeout """ return obj.wait.exists(timeout=timeout) # wait until the ui object gone def wait_until_object_gone(self, obj, timeout=0): """ true means the object disappear false means the object exist in the given timeout """ return obj.wait.gone(timeout=timeout) # Perform fling on the specific ui object(scrollable) def fling_forward_horizontally(self, *args, **selectors): """ return whether the object can be fling or not """ return self.device(**selectors).fling.horiz.forward() def fling_backward_horizontally(self, *args, **selectors): """ return whether the object can be fling or not """ return self.device(**selectors).fling.horiz.backward() def fling_forward_vertically(self, *args, **selectors): """ return whether the object can be fling or not """ return self.device(**selectors).fling.vert.forward() def fling_backward_vertically(self, *args, **selectors): """ return whether the object can be fling or not """ return self.device(**selectors).fling.vert.backward() # Perform scroll on the specific ui object(scrollable) def scroll_to_beginning_vertically(self, steps=10, **selectors): """ """ return self.device(**selectors).scroll.vert.toBeginning(steps=steps) def scroll_to_end_vertically(self, steps=10, **selectors): """ """ return self.device(**selectors).scroll.vert.toEnd(steps=steps) def scroll_object_to_beginning_vertically(self, obj, steps=10): """ """ return obj.scroll.vert.toBeginning(steps=steps) def scroll_object_to_end_vertically(self, obj, steps=10): """ """ return obj.scroll.vert.toEnd(steps=steps) def scroll_forward_horizontally(self, obj, steps=10): """ return whether the object can be scroll or not """ return obj.scroll.horiz.forward(steps=steps) def scroll_backward_horizontally(self, obj, steps=10): """ return whether the object can be scroll or not """ return obj.scroll.horiz.backward(steps=steps) def scroll_to_horizontally(self, obj, *args,**selectors): """ return whether the object can be scroll or not """ return obj.scroll.horiz.to(**selectors) def scroll_forward_vertically(self, obj, steps=10): """ return whether the object can be scroll or not """ return obj.scroll.vert.forward(steps=steps) def scroll_backward_vertically(self, obj, steps=10): """ return whether the object can be scroll or not """ return obj.scroll.vert.backward(steps=steps) def scroll_to_vertically(self, obj, *args, **selectors): """ return whether the object exists or not """ return obj.scroll.vert.to(**selectors) #Screen Actions of the device def get_screen_orientation(self): """ Get the screen orientation. Possible result: natural, left, right, upsidedown See for more details: https://github.com/xiaocong/uiautomator#screen-actions-of-the-device """ return self.device.orientation def set_screen_orientation(self, orientation): """ Set the screen orientation. Input *orientation* : natural or n, left or l, right or r, upsidedown (support android version above 4.3) The keyword will unfreeze the screen rotation first. See for more details: https://github.com/xiaocong/uiautomator#screen-actions-of-the-device Example: | Set Screen Orientation | n | # Set orientation to natural | | Set Screen Orientation | natural | # Do the same thing | """ self.device.orientation = orientation def freeze_screen_rotation(self): """ Freeze the screen auto rotation """ self.device.freeze_rotation() def unfreeze_screen_rotation(self): """ Un-Freeze the screen auto rotation """ self.device.freeze_rotation(False) def screenshot(self, scale=None, quality=None): """ Take a screenshot of device and log in the report with timestamp, scale for screenshot size and quality for screenshot quality default scale=1.0 quality=100 """ output_dir = BuiltIn().get_variable_value('${OUTPUTDIR}') ts = time.time() st = datetime.datetime.fromtimestamp(ts).strftime('%Y%m%d%H%M%S') screenshot_path = '%s%s%s.png' % (output_dir, os.sep, st) self.device.screenshot(screenshot_path, scale, quality) logger.info('\n<a href="%s">%s</a><br><img src="%s">' % (screenshot_path, st, screenshot_path), html=True) #Watcher # def register_click_watcher(self, watcher_name, selectors, *condition_list): # """ # The watcher click on the object which has the selectors when conditions match # """ # print type(selectors) # watcher = self.device.watcher(watcher_name) # for condition in condition_list: # watcher.when(**condition) # watcher.click(**selectors) # self.device.watchers.run() # print 'register watcher:%s' % watcher_name # return def __unicode_to_dict(self, a_unicode): a_dict = dict() dict_item_count = a_unicode.count('=') for count in range(dict_item_count): equal_sign_position = a_unicode.find('=') comma_position = a_unicode.find(',') a_key = a_unicode[0:equal_sign_position] if comma_position == -1: a_value = a_unicode[equal_sign_position + 1:] else: a_value = a_unicode[equal_sign_position + 1:comma_position] a_unicode = a_unicode[comma_position + 1:] a_dict[a_key] = a_value return a_dict def register_click_watcher(self, watcher_name, selectors, *condition_list): """ The watcher click on the object which has the *selectors* when conditions match """ watcher = self.device.watcher(watcher_name) for condition in condition_list: watcher.when(**self.__unicode_to_dict(condition)) watcher.click(**self.__unicode_to_dict(selectors)) self.device.watchers.run() def register_press_watcher(self, watcher_name, press_keys, *condition_list): """ The watcher perform *press_keys* action sequentially when conditions match """ def unicode_to_list(a_unicode): a_list = list() comma_count = a_unicode.count(',') for count in range(comma_count + 1): comma_position = a_unicode.find(',') if comma_position == -1: a_list.append(str(a_unicode)) else: a_list.append(a_unicode[0:comma_position]) a_unicode = a_unicode[comma_position + 1:] return a_list watcher = self.device.watcher(watcher_name) for condition in condition_list: watcher.when(**self.__unicode_to_dict(condition)) watcher.press(*unicode_to_list(press_keys)) self.device.watchers.run() def remove_watchers(self, watcher_name = None): """ Remove watcher with *watcher_name* or remove all watchers """ if watcher_name == None: self.device.watchers.remove() else: self.device.watchers.remove(watcher_name) def list_all_watchers(self): """ Return the watcher list """ return self.device.watchers #Selector def get_object(self, *args, **selectors): """ Get the UI object with selectors *selectors* See `introduction` for details about identified UI object. """ return self.device(*args, **selectors) def get_count(self, *args, **selectors): """ Return the count of UI object with *selectors* Example: | ${count} | Get Count | text=Accessibility | # Get the count of UI object text=Accessibility | | ${accessibility_text} | Get Object | text=Accessibility | # These two keywords combination | | ${count} | Get Count Of Object | ${accessibility_text} | # do the same thing. | """ obj = self.get_object(**selectors) return self.get_count_of_object(obj) def get_count_of_object(self, obj): """ Return the count of given UI object See `Get Count` for more details. """ return len(obj) def get_info_of_object(self, obj, selector=None): """ return info dictionary of the *obj* The info example: { u'contentDescription': u'', u'checked': False, u'scrollable': True, u'text': u'', u'packageName': u'com.android.launcher', u'selected': False, u'enabled': True, u'bounds': { u'top': 231, u'left': 0, u'right': 1080, u'bottom': 1776 }, u'className': u'android.view.View', u'focusable': False, u'focused': False, u'clickable': False, u'checkable': False, u'chileCount': 1, u'longClickable': False, u'visibleBounds': { u'top': 231, u'left': 0, u'right': 1080, u'bottom': 1776 } } """ if selector: return obj.info.get(selector) else: return obj.info def click(self, *args, **selectors): """ click on the UI object with *selectors* """ self.device(**selectors).click() def long_click(self, *args, **selectors): """ click on the UI object with *selectors* """ self.device(**selectors).long_click() def call(self, obj, method, *args, **selectors): """ This keyword can use object method from original python uiautomator See more details from https://github.com/xiaocong/uiautomator Example: | ${accessibility_text} | Get Object | text=Accessibility | # Get the UI object | | Call | ${accessibility_text} | click | # Call the method of the UI object 'click' | """ func = getattr(obj, method) return func(**selectors) def set_text(self, input_text, *args, **selectors): """ Set *input_text* to the UI object with *selectors* """ self.device(**selectors).set_text(input_text) # Other feature def clear_text(self, *args, **selectors): """ Clear text of the UI object with *selectors* """ while True: target = self.device(**selectors) text = target.info['text'] target.clear_text() remain_text = target.info['text'] if text == '' or remain_text == text: break def open_notification(self): """ open notification Built in support for Android 4.3 (API level 18) Using swipe action as a workaround for API level lower than 18 """ sdk_version = self.device.info['sdkInt'] if sdk_version < 18: height = self.device.info['displayHeight'] self.device.swipe(1, 1, 1, height - 1, 1) else: self.device.open.notification() def open_quick_settings(self): """ open quick settings Work for Android 4.3 above (API level 18) """ self.device.open.quick_settings() def sleep(self, time): """ Sleep(no action) for *time* (in millisecond) """ target = 'wait for %s' % str(time) self.device(text=target).wait.exists(timeout=time) def install(self, apk_path): """ Install apk to the device """ self.adb.cmd('install "%s"' % apk_path) def uninstall(self, package_name): """ Uninstall the APP with *package_name* """ self.adb.cmd('uninstall %s' % package_name) def execute_adb_command(self, cmd): """ Execute adb *cmd* """ return self.adb.cmd(cmd) def execute_adb_shell_command(self,cmd): """ Execute adb shell *cmd* """ return self.adb.shell_cmd(cmd) def type(self, input_text, **selectors): """ Type *text* at current focused UI object """ self.test_helper.send_set_text_cmd(input_text) def start_test_agent(self): """ [Test Agent] Start Test Agent Service """ cmd = 'am start edu.ntut.csie.sslab1321.testagent/edu.ntut.csie.sslab1321.testagent.DummyActivity' self.adb.shell_cmd(cmd) def stop_test_agent(self): """ [Test Agent] Stop Test Agent Service """ cmd = 'am broadcast -a testagent -e action STOP_TESTAGENT' self.adb.shell_cmd(cmd) def connect_to_wifi(self, ssid, password): """ [Test Agent] Connect to *ssid* with *password* """ cmd = 'adb shell am start edu.ntut.csie.sslab1321.testagent/edu.ntut.csie.sslab1321.testagent.DummyActivity' cmd = 'adb shell am broadcast -a testagent -e action CONNECT_TO_WIFI -e ssid WEP -e password 12345' cmd = 'am broadcast -a testagent -e action CONNECT_TO_WIFI -e ssid %s -e password %s' % (ssid, password) self.adb.shell_cmd(cmd) def clear_connected_wifi(self): """ [Test Agent] Clear all existed Wi-Fi connection """ cmd = 'am broadcast -a testagent -e action CLEAR_CONNECTED_WIFIS' self.adb.shell_cmd(cmd) def foo(self): pass # logger.info('\nGot arg %s %s' % (output_dir, st), also_console=True) # clm = CommandLineWriter() # output some messages on console # clm.message(' ') # clm.message(u'中文') # clm.message(u'2----------2') def test(self): pass
class AdbDevice(object): hiddenService = 'com.fuhu.settingshelper/.SettingsHelperService' LIST_SYSTEM = 'system' LIST_ALL = 'all' LIST_3RD_PARTY = '3rd' LIST_RECENT = 'recent' orientation = ['natural', 'left', 'upsidedown', 'right'] def __init__(self, serialno=None): self.lock = threading.Semaphore() self.cmd = AdbCmd(serialno) self.serialno = serialno def connect(self): self.d = Device(self.serialno) self.d.orientation # notify to connect # self.d, self.serialno = ViewClient.connectToDeviceOrExit(serialno=self.serialno) # self.vc = ViewClient(self.d, self.serialno, compresseddump=False, ignoreuiautomatorkilled=True, autodump=False) def startActivity(self, component): component = component.replace('$', '\$') self.cmd.shell(['am', 'start', '-n', component, '--activity-clear-task']) def isConnected(self): if self.__getDevices(self.serialno): return True else: return False def listPackages(self): return self.cmd.shell(['pm', 'list', 'package'], output=True) def reboot(self): self.cmd.reboot() def dump(self, compressed=False): return self.d.dump(compressed=compressed).encode('utf-8') @staticmethod def retrieveSelector(point, selectors): shortestDistance = 500000 result = None for selector in selectors: print selector.className bounds = selector.info['bounds'] if bounds['right'] >= point[0] >= bounds['left'] and bounds['top'] >= point[1] >= bounds['bottom']: return selector for selector in selectors: bounds = selector.info['bounds'] distance = (((bounds['left'] + bounds['top']) / 2 - point[0]) ** 2 + ( (bounds['left'] + bounds['bottom']) / 2 - point[1]) ** 2) ** 0.5 if shortestDistance > distance: shortestDistance = distance result = selector return result def checkSamePoint(self, point, info, isLongClick=False): if not self.isScreenOn(): self.powerBtn() if self.isLocked(): self.unlock() if len(info) == 2: if self.d.info['currentPackageName'] == info['packageName']: self.cmd.shell(['input', 'tap', str(point[0]), str(point[1])]) return {'answer': True, 'reason': 'it is the navigation bar'} else: return {'answer': False, 'reason': 'unknown view'} if info['content-desc'] != '': uiObject = self.d(description=info['content-desc']) if self.__checkIncludePoint(uiObject, point): self.cmd.shell(['input', 'tap', str(point[0]), str(point[1])]) else: uiObject.click() return {'answer': True, 'reason': 'find by description'} if info['text'] != '': uiObject = self.d(text=info['text']) if self.__checkIncludePoint(uiObject, point): self.cmd.shell(['input', 'tap', str(point[0]), str(point[1])]) else: uiObject.click() return {'answer': True, 'reason': 'find by text'} currentViewMap = self.getTouchViewInfo(point) if currentViewMap: if currentViewMap['package'] == info['package']: if currentViewMap['class'] == info['class']: self.d.click(point[0], point[1]) return {'answer': True, 'reason': 'Find the similar view'} else: return {'answer': False, 'reason': 'the view doesn\'t be found.'} else: return {'answer': False, 'reason': 'In the wrong page'} else: return {'answer': False, 'reason': 'the view can\'t be found.'} @staticmethod def __checkIncludePoint(uiObject, point): bounds = uiObject.info['visibleBounds'] result, _ = AdbDevice._parseRange(point, (int(bounds['top']), int(bounds['left'])), (int(bounds['right']), int(bounds['bottom']))) return result @staticmethod def removeKey(d, keys): r = dict(d) for k in keys: if r.has_key(k): del r[k] return r def __getDevices(self, serial): outputRE = re.compile(serial) devices = outputRE.findall(AdbCmd.devices()) if len(devices) > 0: return devices[0] def getTouchViewInfo(self, point, compressed=False): smallestArea = sys.maxint result = None root = ET.fromstring(self.dump(compressed=compressed)) for node in root.iter('node'): print node.get('bounds') bounds = re.match('\[(?P<x1>[\d]+),(?P<y1>[\d]+)\]\[(?P<x2>[\d]+),(?P<y2>[\d]+)\]', node.get('bounds')) if bounds: isInclude, area = AdbDevice._parseRange(point, (int(bounds.group('x1')), int(bounds.group('y1'))), (int(bounds.group('x2')), int(bounds.group('y2')))) if isInclude: if area <= smallestArea: smallestArea = area result = node if result is not None: return result.attrib elif point[1] > self.d.info['displayHeight']: p = {'packageName': self.d.info['currentPackageName'], 'type': 'Navigation Bar'} return p @staticmethod def getBoundsCenter(bounds): bounds = re.match('\[(?P<x1>[\d]+),(?P<y1>[\d]+)\]\[(?P<x2>[\d]+),(?P<y2>[\d]+)\]', bounds) x = (int(bounds.group('x2')) + int(bounds.group('x1'))) / 2 y = (int(bounds.group('y2')) + int(bounds.group('y1'))) / 2 return x, y @staticmethod def _parseRange(point, point1, point2): if point1[0] <= point[0] <= point2[0] and point1[1] <= point[1] <= point2[1]: area = (point2[0] - point1[0]) * (point2[1] - point1[1]) return True, area else: return False, None def viewFilter(self, view): if view.getClass() == self.viewClass: return True else: return False def screenOn(self, status): if status == True: self.d.screen.on() else: self.d.screen.off() def clearLog(self): self.cmd.shell(['logcat', '-c']) def longClick(self, x, y, duration): if y <= self.d.info['displayHeight']: self.d.swipe(x, y, x, y, steps=duration / 10) else: self.cmd.shell(['input', 'tap', str(x), str(y)]) def click(self, x, y): if y <= self.d.info['displayHeight']: self.d.click(x, y) else: self.cmd.shell(['input', 'tap', str(x), str(y)]) def drag(self, x, y, duration): self.d.drag(x[0], x[1], y[0], y[1], steps=duration / 10) def swipe(self, x, y, duration): self.cmd.shell(['input', 'swipe', str(x[0]), str(x[1]), str(y[0]), str(y[1]), str(duration)]) def type(self, text): translate = re.sub(r'([#\(\)\&\*\'\\\"\~\`\|\<\>?\;])', r'\\\1', text) self.cmd.shell(['input', 'text', translate]) # self.d(className="android.widget.EditText").set_text(text) def hideKeyboard(self): if self.isKeyboardShown(): self.backBtn() def unlock(self): if self.isLocked(): self.menuBtn() def isLocked(self): lockScreenRE = re.compile('mShowingLockscreen=(true|false)') m = lockScreenRE.search(self.cmd.dumpsys(['window', 'policy'])) if m is not None: return m.group(1) == 'true' def isScreenOn(self): screenOnRE = re.compile('mScreenOnFully=(true|false)') m = screenOnRE.search(self.cmd.dumpsys(['window', 'policy'])) if m is not None: return m.group(1) == 'true' def powerBtn(self): self.cmd.inputKeyevnt('POWER') def backBtn(self): self.cmd.inputKeyevnt('BACK') def homeBtn(self): self.cmd.inputKeyevnt('HOME') def menuBtn(self): self.cmd.inputKeyevnt('MENU') # def rotate(self, orient): # if orient == 'auto': # self.d.freeze_rotation(False) # elif orient == '0': # self.d.orientation = 'n' # elif orient == '90': # self.d.orientation = 'l' # elif orient == '180': # self.d.freeze_rotation(True) # self._setScreenOrient(2) # elif orient == '270': # self.d.orientation = 'r' def rotate(self, orient): self.d.freeze_rotation(True) index = self.orientation.index(self.d.orientation) if orient == 'left': index -= 1 if index < 0: self._setScreenOrient(len(self.orientation) - 1) else: self._setScreenOrient(index) elif orient == 'right': index += 1 if index >= len(self.orientation): self._setScreenOrient(0) else: self._setScreenOrient(index) def volumeUp(self): self.cmd.inputKeyevnt('VOLUME_UP') def volumeDown(self): self.cmd.inputKeyevnt('VOLUME_DOWN') # def _setAutoRotate(self, status): # if status: # self.cmd.shell(['content', 'insert', '--uri', 'content://settings/system', '--bind', 'name:s:accelerometer_rotation', # '--bind', 'value:i:1']) # time.sleep(1) # self.cmd.shell(['content', 'insert', '--uri', 'content://settings/system', '--bind', 'name:s:accelerometer_rotation', # '--bind', 'value:i:1']) # # else: # self.cmd.shell(['content', 'insert', '--uri', 'content://settings/system', '--bind', 'name:s:accelerometer_rotation', # '--bind', 'value:i:0']) # time.sleep(1) # self.cmd.shell(['content', 'insert', '--uri', 'content://settings/system', '--bind', 'name:s:accelerometer_rotation', # '--bind', 'value:i:0']) def _setScreenOrient(self, orient): self.cmd.shell(['content', 'insert', '--uri', 'content://settings/system', '--bind', 'name:s:user_rotation', '--bind', 'value:i:' + str(orient)]) def resetPackage(self, package): self.cmd.shell(['pm', 'clear', package]) def takeSnapshot(self, path): ''' screen capture in png format :param path: saved file path :return: None ''' p1 = self.cmd.popen(['screencap', '-p'], stdout=PIPE) p = Popen(['perl', '-pe', 's/\x0D\x0D\x0A/\x0A/g'], stdin=p1.stdout, stdout=PIPE) out, error = p.communicate() ba = QByteArray.fromRawData(out) img = QImage.fromData(ba, 'PNG') orient = self.getCurrDisplay()['orientation'] if orient == 1: img = img.transformed(QMatrix().rotate(-90)) elif orient == 2: img = img.transformed(QMatrix().rotate(-180)) elif orient == 3: img = img.transformed(QMatrix().rotate(-270)) img.save(path, 'PNG') def getCurrDisplay(self): output = self.cmd.dumpsys(['display']) match = re.search('mCurrentOrientation=(?P<orientation>[\d])[\w\d\s\(\),-=]+' + 'mCurrentDisplayRect=Rect\(0, 0 - (?P<width>[\d]+),\s+(?P<height>[\d]+)', output) if match: width = int(match.group('width')) height = int(match.group('height')) orientation = int(match.group('orientation')) mode = 'landscape' if width > height else 'portrait' return {'width': width, 'height': height, 'orientation': orientation, 'mode': mode} def getRealDisplay(self): output = self.cmd.dumpsys(['display']) match = re.search('real\s(?P<width>[\d]+)\sx\s(?P<height>[\d]+)', output) return {'width': int(match.group('width')), 'height': int(match.group('height'))} def getProp(self, propType=None): if propType: return self.cmd.getProp(propType) else: return self.cmd.getProp(propType) def uninstall(self, package): self.cmd.uninstall(package) def install(self, name): self.cmd.install(name) def close(self): pass def checkConnected(self): return self.d.checkConnected() def extractComponentName(self, packageName): if packageName == 'com.google.android.youtube': return 'com.google.android.youtube/.app.honeycomb.Shell$HomeActivity' output = self.cmd.dumpsys(['package', packageName]) try: if os.name == 'nt': splitOutput = output.split('\r\r\n') else: splitOutput = output.split('\r\n') num = splitOutput.index(next(x for x in splitOutput if x.find('android.intent.action.MAIN:') != -1)) if num != -1: print splitOutput[num + 1] return splitOutput[num + 1].split()[1] else: return None except: return None def screenTimeout(self): timeout = self.cmd.getSettings(['system', 'screen_off_timeout']) return long(timeout) / 1000 def setScreenTimeout(self, value): self.cmd.putSettings(['system', 'screen_off_timeout', value]) def isNfcOn(self): match = re.search('mState=(on|off)', self.cmd.dumpsys(['nfc'])) if match: if match.group(1) == 'on': return True else: return False else: return False def isAirPlaneModeOn(self): match = re.search('(0|1)', self.cmd.getSettings(['global', 'airplane_mode_on'])) if match: if match.group(1) == '1': return True else: return False def isInstallUnknownSources(self): match = re.search('(0|1)', self.cmd.getSettings(['global', 'install_non_market_apps'])) if match: if match.group(1) == '1': return True else: return False def isKeyboardShown(self): output = self.cmd.dumpsys(['input_method']) result = re.search('mInputShown=(true|false)', output) if result.group(1) == 'true': return True else: return False def isWifiOn(self): match = re.search('(0|1)', self.cmd.getSettings(['global', 'wifi_on'])) if match: if match.group(1) == '1': return True else: return False def isBtOn(self): match = re.search('(0|1)', self.cmd.getSettings(['global', 'bluetooth_on'])) if match: if match.group(1) == '1': return True else: return False def isNoKeepActivityOn(self): match = re.search('(0|1)', self.cmd.getSettings(['global', 'always_finish_activities'])) if match: if match.group(1) == '1': return True else: return False def isDataRoamingOn(self): match = re.search('(0|1)', self.cmd.getSettings(['global', 'data_roaming'])) if match: if match.group(1) == '1': return True else: return False def isAutoRotateOn(self): match = re.search('(0|1)', self.cmd.getSettings(['system', 'accelerometer_rotation'])) if match: if match.group(1) == '1': return True else: return False def isGpsOn(self): state = self.cmd.getSettings(['secure', 'location_providers_allowed']) if state == 'none': return False else: return True def isAutoBrightnessOn(self): match = re.search('(0|1)', self.cmd.getSettings(['system', 'screen_brightness_mode'])) if match: if match.group(1) == '1': return True else: return False def isVibrateWhenRingOn(self): match = re.search('(0|1)', self.cmd.getSettings(['system', 'vibrate_when_ringing'])) if match: if match.group(1) == '1': return True else: return False else: return False def isWindowAniOn(self): match = re.search('(0.0|1.0)', self.cmd.getSettings(['global', 'window_animation_scale'])) if match: if match.group(1) == '0.0': return True else: return False else: return False def isTransitionAnuOn(self): match = re.search('(0.0|1.0)', self.cmd.getSettings(['global', 'transition_animation_scale'])) if match: if match.group(1) == '0.0': return True else: return False else: return False def isDurationAniOn(self): match = re.search('(0.0|1.0)', self.cmd.getSettings(['global', 'animator_duration_scale'])) if match: if match.group(1) == '0.0': return True else: return False else: return False def enableWifi(self, state): if state: self.cmd.shell(['am', 'startservice', '--ez', 'wifi', 'true', '-n', self.hiddenService]) else: self.cmd.shell(['am', 'startservice', '--ez', 'wifi', 'false', '-n', self.hiddenService]) def enableBluetooth(self, state): if state: self.cmd.shell(['am', 'startservice', '--ez', 'bt', 'true', '-n', self.hiddenService]) else: self.cmd.shell(['am', 'startservice', '--ez', 'bt', 'false', '-n', self.hiddenService]) def enableInstallUnknownSources(self, state): if state: self.cmd.putSettings(['global', 'install_non_market_apps', '1']) else: self.cmd.putSettings(['global', 'install_non_market_apps', '0']) def enableNfc(self, state): if state: self.cmd.shell(['service', 'call', 'nfc', '6']) else: self.cmd.shell(['service', 'call', 'nfc', '5']) def enableNoKeepActivity(self, state): if state: self.cmd.putSettings(['global', 'always_finish_activities', '1']) else: self.cmd.putSettings(['global', 'always_finish_activities', '0']) def enableDataRoaming(self, state): if state: self.cmd.putSettings(['global', 'data_roaming', '1']) else: self.cmd.putSettings(['global', 'data_roaming', '0']) def enableAutoRotate(self, state): if state: self.cmd.putSettings(['system', 'accelerometer_rotation', '1']) else: self.cmd.putSettings(['system', 'accelerometer_rotation', '0']) def enableGps(self, state): if state: self.cmd.putSettings(['secure', 'location_providers_allowed', 'gps,network']) else: self.cmd.putSettings(['secure', 'location_providers_allowed', 'none']) def enableAutoBrightness(self, state): if state: self.cmd.putSettings(['system', 'screen_brightness_mode', '1']) else: self.cmd.putSettings(['system', 'screen_brightness_mode', '0']) def enableVibrateRinging(self, state): if state: self.cmd.putSettings(['system', 'vibrate_when_ringing', '1']) else: self.cmd.putSettings(['system', 'vibrate_when_ringing', '0']) def enableVibrateWhenRing(self, state): if state: self.cmd.putSettings(['system', 'vibrate_when_ringing', '1']) else: self.cmd.putSettings(['system', 'vibrate_when_ringing', '0']) def enableWindowAnimator(self, state): if state: self.cmd.putSettings(['global', 'window_animation_scale', '1.0']) else: self.cmd.putSettings(['global', 'window_animation_scale', '0.0']) def enableTransitionAnimator(self, state): if state: self.cmd.putSettings(['global', 'transition_animation_scale', '1.0']) else: self.cmd.putSettings(['global', 'transition_animation_scale', '0.0']) def enableDurationAnimation(self, state): if state: self.cmd.putSettings(['global', 'animator_duration_scale', '1.0']) else: self.cmd.putSettings(['global', 'animator_duration_scale', '0.0']) def enableAirplaneMode(self, state): if state: self.cmd.putSettings(['global', 'airplane_mode_on', '1']) self.cmd.shell(['am', 'broadcast', '-a', 'android.intent.action.AIRPLANE_MODE', '--ez', 'state', 'true']) else: self.cmd.putSettings(['global', 'airplane_mode_on', '0']) self.cmd.shell(['am', 'broadcast', '-a', 'android.intent.action.AIRPLANE_MODE', '--ez', 'state', 'false']) def requestPackage(self, t): result = None if t == self.LIST_ALL: result = self.cmd.shell(['pm', 'list', 'packages'], output=True) elif t == self.LIST_SYSTEM: result = self.cmd.shell(['pm', 'list', 'packages', '-s'], output=True) elif t == self.LIST_3RD_PARTY: result = self.cmd.shell(['pm', 'list', 'packages', '-3'], output=True) if result: packages = result.split('\r\n') packages.remove('') packages.sort() return packages def getSerialNumber(self): return self.serialno
class Mobile(): """ robotframework-uiautomatorlibrary is an Android device testing library for Robot Framework. It uses uiautomator - Python wrapper for Android uiautomator tool (https://pypi.python.org/pypi/uiautomator/0.1.28) internally. *Before running tests* You can use `Set Serial` to specify which device to perform the test. *Identify UI object* There are two kinds of keywords. """ __version__ = '0.1' ROBOT_LIBRARY_DOC_FORMAT = 'ROBOT' ROBOT_LIBRARY_SCOPE = 'GLOBAL' def set_serial(self, android_serial): """ Specify given *android_serial* device to perform test. You do not have to specify the device when there is only one device connects to the computer. When you need to use multiple devices, do not use this keyword to switch between devices in test execution. Using different library name when importing this library according to http://robotframework.googlecode.com/hg/doc/userguide/RobotFrameworkUserGuide.html?r=2.8.4#setting-custom-name-to-test-library. | Setting | Value | Value | Value | | Library | Mobile | WITH NAME | Mobile1 | | Library | Mobile | WITH NAME | Mobile2 | And set the serial to each library. | Test Case | Action | Argument | | Multiple Devices | Mobile1.Set Serial | device_1's serial | | | Mobile2.Set Serial | device_2's serial | """ self.adb = ADB(android_serial) self.device = Device(android_serial) self.test_helper = TestHelper(self.adb) def get_device_info(self): """ Retrieve the device info. The keyword will return a dictionary. You can log the information by using the log dictionary keyword in build in Collections library(http://robotframework.googlecode.com/hg/doc/libraries/Collections.html?r=2.8.4). Example: | ${device_info} | Get Device Info | | Log Dictionary | ${device_info} | => Dictionary size is 9 and it contains following items:\n currentPackageName: com.android.keyguard\n displayHeight: 1776\n displayRotation: 0\n displaySizeDpX: 360\n displaySizeDpY: 640\n displayWidth: 1080\n naturalOrientation: True\n productName: hammerhead\n sdkInt: 19\n Or get specific information of the device by giving the key. | ${device_info} | Get Device Info | | | | ${product_name} | Get From Dictionary | ${device_info} | productName | => ${product_name} = hammerhead """ return self.device.info #Key Event Actions of the device """ Turn on/off screen """ def turn_on_screen(self): """ Turn on screen """ self.device.screen.on() def turn_off_screen(self): """ Turn off screen """ self.device.screen.off() """ Press hard/soft key """ def press_key(self, *keys): """ Press *key* keycode. You can find all keycode in http://developer.android.com/reference/android/view/KeyEvent.html Example: |Press Key | """ self.device.press(*keys) def press_home(self): """ Press home key """ self.device.press.home() def press_back(self): """ Press back key """ self.device.press.back() def press_left(self): """ Press left key """ self.device.pres.left() def press_right(self): """ Press right key """ self.device.press.right() def press_up(self): """ Press up key """ self.device.press.up() def press_down(self): """ Press down key """ self.device.press.down() def press_center(self): """ Press center key """ self.device.press.center() def press_menu(self): """ Press menu key """ self.device.press.menu() def press_search(self): """ Press search key """ self.device.press.search() def press_enter(self): """ Press enter key """ self.device.press.enter() def press_delete(self): """ Press delete key """ self.device.press.delete() def press_recent(self): """ Press recent key """ self.device.press.recent() def press_volume_up(self): """ Press volume up key """ self.device.press.volume_up() def press_volume_down(self): """ Press volume down key """ self.device.press.volume_down() def press_camera(self): """ Press camera key """ self.device.press.camera() def press_power(self): """ Press power key """ self.device.press.power() #Gesture interaction of the device def click_at_coordinates(self, x, y): """ Click at (x,y) coordinates. """ self.device.click(x, y) def swipe_by_coordinates(self, sx, sy, ex, ey, steps=100): """ Swipe from (sx, sy) to (ex, ey) with *steps* . """ self.device.swipe(sx, sy, ex, ey, steps) # Swipe from the center of the ui object to its edge def swipe_left(self, steps=100, *args, **attributes): """ Swipe the UI object with *attributes* from center to left. """ self.device(**attributes).swipe.left(steps=steps) def swipe_right(self, steps=100, *args, **attributes): """ Swipe the UI object with *attributes* from center to right """ self.device(**attributes).swipe.right(steps=steps) def swipe_top(self, steps=100, *args, **attributes): """ Swipe the UI object with *attributes* from center to top """ self.device(**attributes).swipe.up(steps=steps) def swipe_bottom(self, steps=100, *args, **attributes): """ Swipe the UI object with *attributes* from center to bottom """ self.device(**attributes).swipe.down(steps=steps) def object_swipe_left(self, obj, steps=100): """ Swipe the *obj* from center to left """ obj.swipe.left(steps=steps) def object_swipe_right(self, obj, steps=100): """ Swipe the *obj* from center to right """ obj.swipe.right(steps=steps) def object_swipe_top(self, obj, steps=100): """ Swipe the *obj* from center to top """ obj.swipe.up(steps=steps) def object_swipe_bottom(self, obj, steps=100): """ Swipe the *obj* from center to bottom """ obj.swipe.down(steps=steps) def drag(self,sx, sy, ex, ey, steps=100): """ drag from (sx, sy) to (ex, ey) with steps """ self.device.drag(sx, sy, ex, ey, steps) #Wait until the specific ui object appears or gone # wait until the ui object appears def wait_for_exists(self, timeout=0, *args, **attribute): """ true means the object which has *attribute* exist false means the object does not exist in the given timeout """ return self.device(**attribute).wait.exists(timeout=timeout) # wait until the ui object gone def wait_until_gone(self, timeout=0, *args, **attribute): """ true means the object which has *attribute* disappear false means the object exist in the given timeout """ return self.device(**attribute).wait.gone(timeout=timeout) def wait_for_object_exists(self, obj, timeout=0): """ true means the object exist false means the object does not exist in the given timeout """ return obj.wait.exists(timeout=timeout) # wait until the ui object gone def wait_until_object_gone(self, obj, timeout=0): """ true means the object disappear false means the object exist in the given timeout """ return obj.wait.gone(timeout=timeout) # Perform fling on the specific ui object(scrollable) def fling_forward_horizontally(self, obj): """ return whether the object can be fling or not """ return obj.fling.horiz.forward() def fling_backward_horizontally(self, obj): """ return whether the object can be fling or not """ return obj.fling.horiz.backward() def fling_forward_vertically(self, obj): """ return whether the object can be fling or not """ return obj.fling.vert.forward() def fling_backward_vertically(self, obj): """ return whether the object can be fling or not """ return obj.fling.vert.backward() # Perform scroll on the specific ui object(scrollable) def scroll_to_beginning_vertically(self, steps=10, **attributes): """ """ return self.device(**attributes).scroll.vert.toBeginning(steps=steps) def scroll_to_end_vertically(self, steps=10, **attributes): """ """ return self.device(**attributes).scroll.vert.toEnd(steps=steps) def scroll_object_to_beginning_vertically(self, obj, steps=10): """ """ return obj.scroll.vert.toBeginning(steps=steps) def scroll_object_to_end_vertically(self, obj, steps=10): """ """ return obj.scroll.vert.toEnd(steps=steps) def scroll_forward_horizontally(self, obj, steps=10): """ return whether the object can be scroll or not """ return obj.scroll.horiz.forward(steps=steps) def scroll_backward_horizontally(self, obj, steps=10): """ return whether the object can be scroll or not """ return obj.scroll.horiz.backward(steps=steps) def scroll_to_horizontally(self, obj, *args,**attribute): """ return whether the object can be scroll or not """ return obj.scroll.horiz.to(**attribute) def scroll_forward_vertically(self, obj, steps=10): """ return whether the object can be scroll or not """ return obj.scroll.vert.forward(steps=steps) def scroll_backward_vertically(self, obj, steps=10): """ return whether the object can be scroll or not """ return obj.scroll.vert.backward(steps=steps) def scroll_to_vertically(self, obj, *args, **attribute): """ return whether the object exists or not """ return obj.scroll.vert.to(**attribute) #Screen Actions of the device def screenshot(self, scale=None, quality=None): """ Take a screenshot of device and log in the report with timestamp, scale for screenshot size and quality for screenshot quality default scale=1.0 quality=100 """ output_dir = BuiltIn().get_variable_value('${OUTPUTDIR}') ts = time.time() st = datetime.datetime.fromtimestamp(ts).strftime('%Y%m%d%H%M%S') screenshot_path = '%s%s%s.png' % (output_dir, os.sep, st) self.device.screenshot(screenshot_path, scale, quality) logger.info('\n<a href="%s">%s</a><br><img src="%s">' % (screenshot_path, st, screenshot_path), html=True) #Watcher # def register_click_watcher(self, watcher_name, attributes, *condition_list): # """ # The watcher click on the object which has the attributes when conditions match # """ # print type(attributes) # watcher = self.device.watcher(watcher_name) # for condition in condition_list: # watcher.when(**condition) # watcher.click(**attributes) # self.device.watchers.run() # print 'register watcher:%s' % watcher_name # return def __unicode_to_dict(self, a_unicode): a_dict = dict() dict_item_count = a_unicode.count('=') for count in range(dict_item_count): equal_sign_position = a_unicode.find('=') comma_position = a_unicode.find(',') a_key = a_unicode[0:equal_sign_position] if comma_position == -1: a_value = a_unicode[equal_sign_position + 1:] else: a_value = a_unicode[equal_sign_position + 1:comma_position] a_unicode = a_unicode[comma_position + 1:] a_dict[a_key] = a_value return a_dict def register_click_watcher(self, watcher_name, attributes, *condition_list): """ The watcher click on the object which has the *attributes* when conditions match """ watcher = self.device.watcher(watcher_name) for condition in condition_list: watcher.when(**self.__unicode_to_dict(condition)) watcher.click(**self.__unicode_to_dict(attributes)) self.device.watchers.run() def register_press_watcher(self, watcher_name, press_keys, *condition_list): """ The watcher perform *press_keys* action sequentially when conditions match """ def unicode_to_list(a_unicode): a_list = list() comma_count = a_unicode.count(',') for count in range(comma_count + 1): comma_position = a_unicode.find(',') if comma_position == -1: a_list.append(str(a_unicode)) else: a_list.append(a_unicode[0:comma_position]) a_unicode = a_unicode[comma_position + 1:] return a_list watcher = self.device.watcher(watcher_name) for condition in condition_list: watcher.when(**self.__unicode_to_dict(condition)) watcher.press(*unicode_to_list(press_keys)) self.device.watchers.run() def remove_watchers(self, watcher_name = None): """ Remove watcher with *watcher_name* or remove all watchers """ if watcher_name == None: self.device.watchers.remove() else: self.device.watchers.remove(watcher_name) def list_all_watchers(self): """ return the watcher list """ return self.device.watchers #Selector def get_object(self, *args, **attribute): """ Get the ui object with attribute *attribute* """ return self.device(*args, **attribute) def get_count_of_object(self, obj): """ Return the count of given *obj* """ return len(obj) def get_info_of_object(self, obj, attribute=None): """ return info dictionary of the *obj* The info example: { u'contentDescription': u'', u'checked': False, u'scrollable': True, u'text': u'', u'packageName': u'com.android.launcher', u'selected': False, u'enabled': True, u'bounds': { u'top': 231, u'left': 0, u'right': 1080, u'bottom': 1776 }, u'className': u'android.view.View', u'focusable': False, u'focused': False, u'clickable': False, u'checkable': False, u'chileCount': 1, u'longClickable': False, u'visibleBounds': { u'top': 231, u'left': 0, u'right': 1080, u'bottom': 1776 } } """ if attribute: return obj.info.get(attribute) else: return obj.info def click_on(self, *args, **attribute): """ click on the object with *attribute* """ self.device(**attribute).click() def long_click_on(self, *args, **attribute): """ click on the object with *attribute* """ self.device(**attribute).long_click() def call(self, obj, method, *args, **attribute): func = getattr(obj, method) return func(**attribute) def set_text(self, input_text, *args, **attribute): """ set *text* to the Component which has the *attribute* """ self.device(**attribute).set_text(input_text) # Other feature def clear_text(self, *args, **attributes): """ Clear text of the component with *attributes* """ while True: target = self.device(**attributes) text = target.info['text'] target.clear_text() remain_text = target.info['text'] if text == '' or remain_text == text: break def open_notification(self): """ open notification Built in support for Android 4.3 (API level 18) Using swipe action as a workaround for API level lower 18 """ sdk_version = self.device.info['sdkInt'] if sdk_version < 18: height = self.device.info['displayHeight'] self.device.swipe(1, 1, 1, height - 1, 1) else: self.device.open.notification() def open_quick_settings(self): """ open quick settings Work for Android 4.3 (API level 18) """ self.device.open.quick_settings() def sleep(self, time): """ sleep(no action) for *time* (in millisecond) """ target = 'wait for %s' % str(time) self.device(text=target).wait.exists(timeout=time) def install(self, apk_path): """ Install apk to the device """ self.adb.cmd('install "%s"' % apk_path) def uninstall(self, package_name): """ Uninstall the APP with *package_name* """ self.adb.cmd('uninstall %s' % package_name) def execute_adb_command(self, cmd): """ Execute adb *cmd* """ self.adb.cmd(cmd) def execute_adb_shell_command(self,cmd): """ Execute adb shell *cmd* """ self.adb.shell_cmd(cmd) def type(self, text): """ Type *text* at current focused component """ self.test_helper.send_set_text_cmd(text) def start_test_agent(self): """ [Test Agent] Start Test Agent Service """ cmd = 'am start edu.ntut.csie.sslab1321.testagent/edu.ntut.csie.sslab1321.testagent.DummyActivity' self.adb.shell_cmd(cmd) def stop_test_agent(self): """ [Test Agent] Stop Test Agent Service """ cmd = 'am broadcast -a testagent -e action STOP_TESTAGENT' self.adb.shell_cmd(cmd) def connect_to_wifi(self, ssid, password): """ [Test Agent] Connect to *ssid* with *password* """ cmd = 'adb shell am start edu.ntut.csie.sslab1321.testagent/edu.ntut.csie.sslab1321.testagent.DummyActivity' cmd = 'adb shell am broadcast -a testagent -e action CONNECT_TO_WIFI -e ssid WEP -e password 12345' cmd = 'am broadcast -a testagent -e action CONNECT_TO_WIFI -e ssid %s -e password %s' % (ssid, password) self.adb.shell_cmd(cmd) def clear_connected_wifi(self): """ [Test Agent] Clear all existed Wi-Fi connection """ cmd = 'am broadcast -a testagent -e action CLEAR_CONNECTED_WIFIS' self.adb.shell_cmd(cmd) def foo(self): pass # logger.info('\nGot arg %s %s' % (output_dir, st), also_console=True) # clm = CommandLineWriter() # output some messages on console # clm.message(' ') # clm.message(u'中文') # clm.message(u'2----------2') def test(self): pass
class ModelInfo(): ''' classdocs ''' def __init__(self, deviceserial): ''' Constructor ''' #sndLog = CLS("test", "test") self.osType = sys.platform self.mstrInfo = {} #self.devSerials = self.instAdb.device_serial() self.mstrDevice = Device(deviceserial) self.mstrInfo = self.mstrDevice.info ''' DEVICE Infoamtions { u'displayRotation': 0, u'displaySizeDpY': 640, u'displaySizeDpX': 360, u'currentPackageName': u'com.android.launcher', u'productName': u'takju', u'displayWidth': 720, u'sdkInt': 18, u'displayHeight': 1184, u'naturalOrientation': True } ''' def getCurrntProductInfo(self): return self.mstrInfo def getProductNmae(self): return self.mstrInfo['productName'] def getCurrntPkg(self): return self.mstrInfo['currentPackageName'] def getSDKInt(self): return self.mstrInfo['sdkInt'] def getRotation(self): return self.mstrInfo['displayRotation'] def getNaturalOri(self): return self.mstrInfo['naturalOrientation'] def getDisplayState(self): return self.mstrDevice.screen def setReflash(self): pass #define Key activity def setDevScrnOn(self): self.mstrDevice.screen.on() def setMstDevScrnOff(self): self.mstrDevice.screen.off() def setWakeup(self): self.mstrDevice.wakeup() def setSleep(self): self.mstrDevice.sleep() #Hard key Soft key def pressHome(self): return self.mstrDevice.press.home() def pressBack(self): return self.mstrDevice.press.back() ###################################################################### def pressLeft(self): return self.mstrDevice.press.left() def pressRight(self): return self.mstrDevice.press.right() def pressUp(self): return self.mstrDevice.press.up() def pressDown(self): return self.mstrDevice.press.down() def pressCenter(self): return self.mstrDevice.press.center() ###################################################################### def pressMenu(self): return self.mstrDevice.press.menu() def pressSearch(self): return self.mstrDevice.press.search() def pressEnter(self): return self.mstrDevice.press.enter() def pressDelete(self): return self.mstrDevice.press.delete() # or del def pressRecent(self): return self.mstrDevice.press.recent() def pressVol_Up(self): return self.mstrDevice.press.volume_up() def pressVol_Down(self): return self.mstrDevice.press.volume_down() def pressVol_Mute(self): return self.mstrDevice.press.volume_mute() def pressPower(self): return self.mstrDevice.press.power() def clik(self, x, y): return self.mstrDevice.click(x, y) def longClik(self, x, y): ''' Description: param: x, y : start first point x, y return : Boolean ''' return self.mstrDevice.long_click(x, y) def swipe(self, sx, sy, ex, ey, steps=10): ''' Description: param: sx, xy : start first x, y ex, ey : move to x, y return : Boolean ''' return self.mstrDevice.swipe(sx, sy, ex, ey, steps) def drage(self, sx, sy, ex, ey, steps=10): ''' Description: param: sx, xy : start first x, y ex, ey : move to x, y return : Boolean ''' return self.mstrDevice.drag(sx, sy, ex, ey, steps) #screen action of the device def setOrientation(self, scrAct='natural', choiceDevice='mstr'): ''' Description param d.orientation = 'l' or 'left' d.orientation = 'r' or 'right' d.orientation = 'n' or 'natural' return : None ''' self.mstrDevice.orientation = scrAct def setFreezeRotation(self, condition=False, choiceDevice='mstr'): ''' param: condition : False un-freeze rotation return : None ''' self.mstrDevice.freeze_rotation(condition) def takeScreenShot(self, choiceDevice='mstr'): ''' Description: take screenshot and save to local file 'home.png' can work until android 4.2 param image name ''' def dumpWindowHeirarchy(self, filename='./log/hierachy.xml'): return self.mstrDevice.dump(filename) def dumpWindowHeirarchyStream(self): return self.mstrDevice.dump() def notification(self): ''' Open notification, can not work until android 4.3 return : Boolean ''' return self.mstrDevice.open.Notification() def quickSettings(self): ''' open quick settins, can not work until android 4.3 return : Boolean ''' return self.mstrDevice.open.quick_settings() def waitidle(self): ''' wait for current window to idle return : None ''' self.mstrDevice.wait.idle() def waitWindowUpdate(self): ''' wait until window upate event occurs return : Boolean ''' self.mstrDevice.wait.update() def getCurrentActivityInfo(self, text): ''' INFOMATION: { u'contentDescription': u'', u'checked': False, u'scrollable': False, u'text': u'Settings', u'packageName': u'com.android.launcher', u'selected': False, u'enabled': True, u'bounds': {u'top': 385, u'right': 360, u'bottom': 585, u'left': 200}, u'className': u'android.widget.TextView', u'focused': False, u'focusable': True, u'clickable': True, u'chileCount': 0, u'longClickable': True, u'visibleBounds': {u'top': 385, u'right': 360, u'bottom': 585, u'left': 200}, u'checkable': False } ''' return self.mstrDevice(text).info def uiObjExist(self, text): ''' ture if exists, else False ''' return self.mstrDevice.exists(text) def watcher(self): pass def handler(self): pass def selector(self): pass def __del__(self): pass
class AdbDevice(object): hiddenService = 'com.fuhu.settingshelper/.SettingsHelperService' LIST_SYSTEM = 'system' LIST_ALL = 'all' LIST_3RD_PARTY = '3rd' LIST_RECENT = 'recent' orientation = ['natural', 'left', 'upsidedown', 'right'] def __init__(self, serialno=None): self.lock = threading.Semaphore() self.cmd = AdbCmd(serialno) self.serialno = serialno def connect(self): self.d = Device(self.serialno) # self.d, self.serialno = ViewClient.connectToDeviceOrExit(serialno=self.serialno) # self.vc = ViewClient(self.d, self.serialno, compresseddump=False, ignoreuiautomatorkilled=True, autodump=False) def startActivity(self, component): component = component.replace('$', '\$') self.cmd.shell( ['am', 'start', '-n', component, '--activity-clear-task']) def isConnected(self): if self.__getDevices(self.serialno): return True else: return False def listPackages(self): return self.cmd.shell(['pm', 'list', 'package'], output=True) def reboot(self): self.cmd.reboot() def dump(self, compressed=False): return self.d.dump(compressed=compressed).encode('utf-8') @staticmethod def retrieveSelector(point, selectors): shortestDistance = 500000 result = None for selector in selectors: print selector.className bounds = selector.info['bounds'] if point[0] <= bounds['right'] and point[0] >= bounds['left'] and point[1] <= bounds['top'] and point[1] >= \ bounds['bottom']: return selector for selector in selectors: bounds = selector.info['bounds'] distance = ( ((bounds['left'] + bounds['top']) / 2 - point[0])**2 + ((bounds['left'] + bounds['bottom']) / 2 - point[1])**2)**0.5 if shortestDistance > distance: shortestDistance = distance result = selector return result def checkSamePoint(self, point, info, isLongClick=False): print info if not self.isScreenOn(): self.powerBtn() if self.isLocked(): self.unlock() if len(info) == 2: if self.d.info['currentPackageName'] == info['packageName']: self.cmd.shell(['input', 'tap', str(point[0]), str(point[1])]) return {'answer': True, 'reason': 'it is the navigation bar'} if info['content-desc'] != '': self.d(contentDescription=info['content-desc']) return {'answer': True, 'reason': 'find by description'} if info['text'] != '': self.d(text=info['text']).click() return {'answer': True, 'reason': 'find by text'} currentViewMap = self.getTouchViewInfo(point) if currentViewMap: if currentViewMap['package'] == info['package']: if currentViewMap['class'] == info['class']: self.d.click(point[0], point[1]) return {'answer': True, 'reason': 'Find the similar view'} else: return { 'answer': False, 'reason': 'the view doesn\'t be found.' } else: return {'answer': False, 'reason': 'In the wrong page'} else: return {'answer': False, 'reason': 'the view can\'t be found.'} @staticmethod def removeKey(d, keys): r = dict(d) for k in keys: if r.has_key(k): del r[k] return r def __getDevices(self, serial): outputRE = re.compile(serial) devices = outputRE.findall(AdbCmd.devices()) if len(devices) > 0: return devices[0] def getTouchViewInfo(self, point, compressed=False): smallestArea = sys.maxint result = None root = ET.fromstring(self.dump(compressed=compressed)) for node in root.iter('node'): bounds = re.match( '\[(?P<x1>[\d]+),(?P<y1>[\d]+)\]\[(?P<x2>[\d]+),(?P<y2>[\d]+)\]', node.get('bounds')) isInclude, area = self._parseRange( point, (int(bounds.group('x1')), int(bounds.group('y1'))), (int(bounds.group('x2')), int(bounds.group('y2')))) if isInclude: if area <= smallestArea: smallestArea = area result = node if result is not None: return result.attrib elif point[1] > self.d.info['displayHeight']: p = { 'packageName': self.d.info['currentPackageName'], 'type': 'Navigation Bar' } return p @staticmethod def getBoundsCenter(bounds): bounds = re.match( '\[(?P<x1>[\d]+),(?P<y1>[\d]+)\]\[(?P<x2>[\d]+),(?P<y2>[\d]+)\]', bounds) x = (int(bounds.group('x2')) + int(bounds.group('x1'))) / 2 y = (int(bounds.group('y2')) + int(bounds.group('y1'))) / 2 return x, y @staticmethod def _parseRange(point, point1, point2): if point[0] >= point1[0] and point[0] <= point2[0]: if point[1] >= point1[1] and point[1] <= point2[1]: area = (point2[0] - point1[0]) * (point2[1] - point1[1]) return (True, area) else: return (False, None) else: return (False, None) def viewFilter(self, view): if view.getClass() == self.viewClass: return True else: return False def screenOn(self, status): if status == True: self.d.screen.on() else: self.d.screen.off() def clearLog(self): self.cmd.shell(['logcat', '-c']) def longClick(self, x, y, duration): if y <= self.d.info['displayHeight']: self.d.swipe(x, y, x, y, steps=duration / 10) else: self.cmd.shell(['input', 'tap', str(x), str(y)]) def click(self, x, y): if y <= self.d.info['displayHeight']: self.d.click(x, y) else: self.cmd.shell(['input', 'tap', str(x), str(y)]) def drag(self, x, y, duration): self.d.drag(x[0], x[1], y[0], y[1], steps=duration / 10) def swipe(self, x, y, duration): self.cmd.shell([ 'input', 'swipe', str(x[0]), str(x[1]), str(y[0]), str(y[1]), str(duration) ]) def type(self, text): translate = re.sub(r'([#\(\)\&\*\'\\\"\~\`\|\<\>?\;])', r'\\\1', text) self.cmd.shell(['input', 'text', translate]) # self.d(className="android.widget.EditText").set_text(text) def hideKeyboard(self): if self.isKeyboardShown(): self.backBtn() def unlock(self): if self.isLocked(): self.menuBtn() def isLocked(self): lockScreenRE = re.compile('mShowingLockscreen=(true|false)') m = lockScreenRE.search(self.cmd.dumpsys(['window', 'policy'])) if m is not None: return m.group(1) == 'true' def isScreenOn(self): screenOnRE = re.compile('mScreenOnFully=(true|false)') m = screenOnRE.search(self.cmd.dumpsys(['window', 'policy'])) if m is not None: return m.group(1) == 'true' def powerBtn(self): self.cmd.inputKeyevnt('POWER') def backBtn(self): self.cmd.inputKeyevnt('BACK') def homeBtn(self): self.cmd.inputKeyevnt('HOME') def menuBtn(self): self.cmd.inputKeyevnt('MENU') # def rotate(self, orient): # if orient == 'auto': # self.d.freeze_rotation(False) # elif orient == '0': # self.d.orientation = 'n' # elif orient == '90': # self.d.orientation = 'l' # elif orient == '180': # self.d.freeze_rotation(True) # self._setScreenOrient(2) # elif orient == '270': # self.d.orientation = 'r' def rotate(self, orient): self.d.freeze_rotation(True) index = self.orientation.index(self.d.orientation) if orient == 'left': index -= 1 if index < 0: self._setScreenOrient(len(self.orientation) - 1) else: self._setScreenOrient(index) elif orient == 'right': index += 1 if index >= len(self.orientation): self._setScreenOrient(0) else: self._setScreenOrient(index) def volumeUp(self): self.cmd.inputKeyevnt('VOLUME_UP') def volumeDown(self): self.cmd.inputKeyevnt('VOLUME_DOWN') # def _setAutoRotate(self, status): # if status: # self.cmd.shell(['content', 'insert', '--uri', 'content://settings/system', '--bind', 'name:s:accelerometer_rotation', # '--bind', 'value:i:1']) # time.sleep(1) # self.cmd.shell(['content', 'insert', '--uri', 'content://settings/system', '--bind', 'name:s:accelerometer_rotation', # '--bind', 'value:i:1']) # # else: # self.cmd.shell(['content', 'insert', '--uri', 'content://settings/system', '--bind', 'name:s:accelerometer_rotation', # '--bind', 'value:i:0']) # time.sleep(1) # self.cmd.shell(['content', 'insert', '--uri', 'content://settings/system', '--bind', 'name:s:accelerometer_rotation', # '--bind', 'value:i:0']) def _setScreenOrient(self, orient): self.cmd.shell([ 'content', 'insert', '--uri', 'content://settings/system', '--bind', 'name:s:user_rotation', '--bind', 'value:i:' + str(orient) ]) def resetPackage(self, package): self.cmd.shell(['pm', 'clear', package]) def takeSnapshot(self, path): return self.d.screenshot(path) def getCurrDisplay(self): output = self.cmd.dumpsys(['display']) match = re.search( 'mCurrentOrientation=(?P<orientation>[\d])[\w\d\s\(\),-=]+' + 'mCurrentDisplayRect=Rect\(0, 0 - (?P<width>[\d]+),\s+(?P<height>[\d]+)', output) width = int(match.group('width')) height = int(match.group('height')) orientation = int(match.group('orientation')) mode = 'landscape' if width > height else 'portrait' return { 'width': width, 'height': height, 'orientation': orientation, 'mode': mode } def getRealDisplay(self): output = self.cmd.dumpsys(['display']) match = re.search('real\s(?P<width>[\d]+)\sx\s(?P<height>[\d]+)', output) return { 'width': int(match.group('width')), 'height': int(match.group('height')) } def getProp(self, propType=None): if propType: return self.cmd.shell(['getprop', propType], output=True).strip('\n') else: return self.cmd.shell(['getprop'], output=True).strip('\n') def uninstall(self, package): self.cmd.uninstall(package) def install(self, name): self.cmd.install(name) def close(self): pass def checkConnected(self): return self.d.checkConnected() def extractComponentName(self, packageName): if packageName == 'com.google.android.youtube': return 'com.google.android.youtube/.app.honeycomb.Shell$HomeActivity' output = self.cmd.dumpsys(['package', packageName]) try: if os.name == 'nt': splitOutput = output.split('\r\r\n') else: splitOutput = output.split('\r\n') num = splitOutput.index( next(x for x in splitOutput if x.find('android.intent.action.MAIN:') != -1)) if num != -1: print splitOutput[num + 1] return splitOutput[num + 1].split()[1] else: return None except: return None def screenTimeout(self): timeout = self.cmd.getSettings(['system', 'screen_off_timeout']) return long(timeout) / 1000 def setScreenTimeout(self, value): self.cmd.putSettings(['system', 'screen_off_timeout', value]) def isNfcOn(self): match = re.search('mState=(on|off)', self.cmd.dumpsys(['nfc'])) if match: if match.group(1) == 'on': return True else: return False else: return False def isAirPlaneModeOn(self): match = re.search('(0|1)', self.cmd.getSettings(['global', 'airplane_mode_on'])) if match: if match.group(1) == '1': return True else: return False def isInstallUnknownSources(self): match = re.search( '(0|1)', self.cmd.getSettings(['global', 'install_non_market_apps'])) if match: if match.group(1) == '1': return True else: return False def isKeyboardShown(self): output = self.cmd.dumpsys(['input_method']) result = re.search('mInputShown=(true|false)', output) if result.group(1) == 'true': return True else: return False def isWifiOn(self): match = re.search('(0|1)', self.cmd.getSettings(['global', 'wifi_on'])) if match: if match.group(1) == '1': return True else: return False def isBtOn(self): match = re.search('(0|1)', self.cmd.getSettings(['global', 'bluetooth_on'])) if match: if match.group(1) == '1': return True else: return False def isNoKeepActivityOn(self): match = re.search( '(0|1)', self.cmd.getSettings(['global', 'always_finish_activities'])) if match: if match.group(1) == '1': return True else: return False def isDataRoamingOn(self): match = re.search('(0|1)', self.cmd.getSettings(['global', 'data_roaming'])) if match: if match.group(1) == '1': return True else: return False def isAutoRotateOn(self): match = re.search( '(0|1)', self.cmd.getSettings(['system', 'accelerometer_rotation'])) if match: if match.group(1) == '1': return True else: return False def isGpsOn(self): state = self.cmd.getSettings(['secure', 'location_providers_allowed']) if state == 'none': return False else: return True def isAutoBrightnessOn(self): match = re.search( '(0|1)', self.cmd.getSettings(['system', 'screen_brightness_mode'])) if match: if match.group(1) == '1': return True else: return False def isVibrateWhenRingOn(self): match = re.search( '(0|1)', self.cmd.getSettings(['system', 'vibrate_when_ringing'])) if match: if match.group(1) == '1': return True else: return False else: return False def isWindowAniOn(self): match = re.search( '(0.0|1.0)', self.cmd.getSettings(['global', 'window_animation_scale'])) if match: if match.group(1) == '0.0': return True else: return False else: return False def isTransitionAnuOn(self): match = re.search( '(0.0|1.0)', self.cmd.getSettings(['global', 'transition_animation_scale'])) if match: if match.group(1) == '0.0': return True else: return False else: return False def isDurationAniOn(self): match = re.search( '(0.0|1.0)', self.cmd.getSettings(['global', 'animator_duration_scale'])) if match: if match.group(1) == '0.0': return True else: return False else: return False def enableWifi(self, state): if state: self.cmd.shell([ 'am', 'startservice', '--ez', 'wifi', 'true', '-n', self.hiddenService ]) else: self.cmd.shell([ 'am', 'startservice', '--ez', 'wifi', 'false', '-n', self.hiddenService ]) def enableBluetooth(self, state): if state: self.cmd.shell([ 'am', 'startservice', '--ez', 'bt', 'true', '-n', self.hiddenService ]) else: self.cmd.shell([ 'am', 'startservice', '--ez', 'bt', 'false', '-n', self.hiddenService ]) def enableInstallUnknownSources(self, state): if state: self.cmd.putSettings(['global', 'install_non_market_apps', '1']) else: self.cmd.putSettings(['global', 'install_non_market_apps', '0']) def enableNfc(self, state): if state: self.cmd.shell(['service', 'call', 'nfc', '6']) else: self.cmd.shell(['service', 'call', 'nfc', '5']) def enableNoKeepActivity(self, state): if state: self.cmd.putSettings(['global', 'always_finish_activities', '1']) else: self.cmd.putSettings(['global', 'always_finish_activities', '0']) def enableDataRoaming(self, state): if state: self.cmd.putSettings(['global', 'data_roaming', '1']) else: self.cmd.putSettings(['global', 'data_roaming', '0']) def enableAutoRotate(self, state): if state: self.cmd.putSettings(['system', 'accelerometer_rotation', '1']) else: self.cmd.putSettings(['system', 'accelerometer_rotation', '0']) def enableGps(self, state): if state: self.cmd.putSettings( ['secure', 'location_providers_allowed', 'gps,network']) else: self.cmd.putSettings( ['secure', 'location_providers_allowed', 'none']) def enableAutoBrightness(self, state): if state: self.cmd.putSettings(['system', 'screen_brightness_mode', '1']) else: self.cmd.putSettings(['system', 'screen_brightness_mode', '0']) def enableVibrateRinging(self, state): if state: self.cmd.putSettings(['system', 'vibrate_when_ringing', '1']) else: self.cmd.putSettings(['system', 'vibrate_when_ringing', '0']) def enableVibrateWhenRing(self, state): if state: self.cmd.putSettings(['system', 'vibrate_when_ringing', '1']) else: self.cmd.putSettings(['system', 'vibrate_when_ringing', '0']) def enableWindowAnimator(self, state): if state: self.cmd.putSettings(['global', 'window_animation_scale', '1.0']) else: self.cmd.putSettings(['global', 'window_animation_scale', '0.0']) def enableTransitionAnimator(self, state): if state: self.cmd.putSettings( ['global', 'transition_animation_scale', '1.0']) else: self.cmd.putSettings( ['global', 'transition_animation_scale', '0.0']) def enableDurationAnimation(self, state): if state: self.cmd.putSettings(['global', 'animator_duration_scale', '1.0']) else: self.cmd.putSettings(['global', 'animator_duration_scale', '0.0']) def enableAirplaneMode(self, state): if state: self.cmd.putSettings(['global', 'airplane_mode_on', '1']) self.cmd.shell([ 'am', 'broadcast', '-a', 'android.intent.action.AIRPLANE_MODE', '--ez', 'state', 'true' ]) else: self.cmd.putSettings(['global', 'airplane_mode_on', '0']) self.cmd.shell([ 'am', 'broadcast', '-a', 'android.intent.action.AIRPLANE_MODE', '--ez', 'state', 'false' ]) def requestPackage(self, t): result = None if t == self.LIST_ALL: result = self.cmd.shell(['pm', 'list', 'packages'], output=True) elif t == self.LIST_SYSTEM: result = self.cmd.shell(['pm', 'list', 'packages', '-s'], output=True) elif t == self.LIST_3RD_PARTY: result = self.cmd.shell(['pm', 'list', 'packages', '-3'], output=True) if result: packages = result.split('\r\n') packages.remove('') packages.sort() return packages def getSerialNumber(self): return self.serialno
class UiTestLib(object): """Ui Test Lib """ def __init__(self, serial=None): """ """ logger.info("<p>Device=%s>" % serial, html=True) print "<p>Device=%s>" % serial self._result = "" self.starttime = 0 self.d = Device(serial) self.adb = Adb(serial) self.debug = "True" def set_debugable(flag): self.debug = flag def set_serial(self, serial): """Specify given *serial* device to perform test. or export ANDROID_SERIAL=CXFS42343 if you have many devices connected but you don't use this interface When you need to use multiple devices, do not use this keyword to switch between devices in test execution. And set the serial to each library. Using different library name when importing this library according to http://robotframework.googlecode.com/hg/doc/userguide/RobotFrameworkUserGuide.html?r=2.8.5. Examples: | Setting | Value | Value | Value | | Library | UiTestLib | WITH NAME | Mobile1 | | Library | UiTestLib | WITH NAME | Mobile2 | And set the serial to each library. | Test Case | Action | Argument | | Multiple Devices | Mobile1.Set Serial | device_1's serial | | | Mobile2.Set Serial | device_2's serial | """ self.d = Device(serial) self.adb = Adb(serial) def logmsg(self, msg): if self.debug == "True": print msg def exe_adb_command(self, cmd): """ Execute adb *cmd* Examples: | Exe Adb Command | shell getprop | """ return self.adb.cmd(cmd).wait() def exe_adb_and_result(self, cmd): """Execute adb *cmd* and return lines of the command""" lproc = self.adb.cmd(cmd) lproc.poll() lines = lproc.stdout.readlines() return lines def get_device_info(self): """Get Device information return info dictionary """ return self.d.info def light_screen(self): """Light screen by wakeup. Examples: | Action | |Light screen| Use `Light screen` to light screen. """ self.d.wakeup() self._result = self.d.press.home() def open_application(self, appname): """Open application by it name `appname`. Example: | Action | Argument | | Open application | "com.android.settings/com.android.settings.Settings" | """ appname = "shell am start -n " + appname print "Open Application:", appname self._result = self.exe_adb_command(appname) def click_text(self, text, instance=0): """Click text label on screen instance=0 is default, change when you needed. Example: | Action | Argument | Argument | | Click Text | text | instance | """ return self.d(text=text, instance=instance).click.wait() def long_click_text(self, text, instance=0): """ Long Click text label on screen, *text* and *instance=0* Example: | Action | Argument | Argument | | Long Click Text | text | instance | """ return self.d(text=text, instance=instance).long_click() def long_click_ui(self, **selectors): """ Long Click on **selectors** Selector supports below parameters. Refer to UiSelector java doc for detailed information. text, textContains, textMatches, textStartsWith className, classNameMatches description, descriptionContains, descriptionMatches, descriptionStartsWith checkable, checked, clickable, longClickable scrollable, enabled,focusable, focused, selected packageName, packageNameMatches resourceId, resourceIdMatches index, instance Example: | Action | Argument | Argument | Argument | | Long Click UI | text=XXXX | className=XXX.xxxx | resourceId=xxxxxx | """ return self.d(**selectors).long_click() def text_display_on_screen_contains(self, text): """Verify text display on screen Example: | Action | Argument | |Text display on screen is| text | """ if self.d(text=text).exists: self._result = True return True else: self._result = False return False def object_display_on_screen(self, obj, timeout=5000): """ Verify *obj* UiObject display on screen return to self._result Example: | Action | Argument | |Object display on screen | obj | """ if obj.wait.exists(timeout): self._result = True return True else: self._result = False return False def assert_expectation(self, expect, actual): """ Assert Expectation and actual value Example: | Action | args | args | | Assert Expectation | 324324 | ${actual} | """ if str(expect) != str(actual): raise AssertionError("Actual result is = %s, but expectation is: %s" % (str(actual), str(expect))) def assert_true(self, condition): """ Assert True of *condition Example: |Assert True | condition | """ if str(condition) != "True": # because only string from robotframework raise AssertionError("Result is = %s" % str(condition)) def assert_result_true(self): """ Assert True of *self._result Example: |Assert True | """ if self._result != True: raise AssertionError("Result is = %s" % str(self._result)) def wait_for_ui_exists(self, timeout, **selectors): """ Return True if Selector is to identify specific ui object in current window. # To seleted the object ,text is 'Clock' and its className is 'android.widget.TextView' wait_for_ui_exists(text='Clock', className='android.widget.TextView') Selector supports below parameters. Refer to UiSelector java doc for detailed information. text, textContains, textMatches, textStartsWith className, classNameMatches description, descriptionContains, descriptionMatches, descriptionStartsWith checkable, checked, clickable, longClickable scrollable, enabled,focusable, focused, selected packageName, packageNameMatches resourceId, resourceIdMatches index, instance Examples: | Action | Argument | Argument | Argument | Argument | |Wait For UI Exists | timeout | text=XXXX | className=XXX.xxxx | resourceId=xxxxxx | """ self._result = self.d(**selectors).wait.exists(timeout=int(timeout)) return self._result def wait_and_click(self, timeout, **selectors): """Wait for uiselector and click""" if self.d(**selectors).wait.exists(timeout=int(timeout)): self.d(**selectors).click() def assert_ui_exists(self, **selectors): """ Assert UiObject appear on the screen Examples: | Action | Argument | Argument | Argument | Argument | |Assert UI Exists | timeout | text=XXXX | className=XXX.xxxx | resourceId=xxxxxx | """ if not self.d(**selectors).wait.exists(): raise AssertionError("UiObject does not exists %s" % selectors.items()) def result_should_be(self, expected): """Verifies that the current result is `expected`. Example: | Action | Argument | | Open application | com.android.settings/com.android.settings.Settings | | Result Should Be | 0 | """ print ("result is: %s\n", self._result) print ("ex is: %s\n", expected) if str(self._result) != expected: raise AssertionError("%s != %s" % (self._result, expected)) def click_at_coordinates(self, x, y): """ Click at (x,y) coordinates. Example: | Action | Argument | Argument | | Click At Corrdinates | x | y | """ return self.d.click(int(x), int(y)) def long_click_at_coordinates(self, x, y): """ # long click (x, y) on screen """ return self.d.long_click(int(x), int(y)) def swipe(self, sx, sy, ex, ey, steps=20): """ Swipe from (sx,sy) to (ex,ey) """ return self.d.swipe(int(sx), int(sy), int(ex), int(ex), int(steps)) def drag(self, sx, sy, ex, ey, steps=20): """ Drag from (sx,sy) to (ex,ey) """ return self.d.drag(int(sx), int(sy), int(ex), int(ex), int(steps)) def freeze_rotation(self, rotation=True): """ Freeze rotation, *rotation*, True is default, """ return self.d.freeze_rotation(rotation) def set_rotation(self, rotation): """ # retrieve orientation, # it should be "natural" or "left" or "right" or "upsidedown" Example: | Action | Argument | | Set Rotation | nature | | Set Rotation | left | | Set Rotation | right | | Set Rotation | upsidedown | """ orientation = self.d.orientation if rotation == "nature": self.d.orientation = "n" # or "natural" elif rotation == "left": self.d.orientation = "l" # or "left" elif rotation == "right": self.d.orientation = "r" # or "right" elif rotation == "upsidedown": self.d.orientation = "upsidedown" # or "upsidedown" else: self.d.rotation = "n" def take_screenshot(self, scale=None, quality=None): """ Take a screenshot of device and log in the report with timestamp, scale for screenshot size and quality for screenshot quality default scale=1.0 quality=100 Example: | Action | Argument | Argument | | Take Screenshot | 0.5 | 80 | """ output_dir = BuiltIn().get_variable_value("${OUTPUTDIR}") ts = time.time() st = datetime.datetime.fromtimestamp(ts).strftime("%Y%m%d%H%M%S") screenshot_path = "%s%s%s.png" % (output_dir, os.sep, st) screenshot_name = "%s%s.png" % (os.sep, st) self.d.screenshot(screenshot_path, scale, quality) logger.info('\n<a href="%s">%s</a><br><img src="%s">' % (screenshot_path, st, screenshot_name), html=True) def open_notification(self): """ Open notification of the phone """ self.d.open.notification() def wait_window_update(self): """ wait for window update """ return self.d.wait.update() def wait_window_idle(self): """ wait for window idle """ return self.d.wait.idle() def remove_watchers(self): """ Remove UI watchers """ self.d.watchers.remove() def get_device(self): """ Get device object, you can do any command using this """ return self.d def click_id(self, id, instance=0): """ Click *id* with *instance*=0 """ return self.d(resourceId=id, instance=instance).click.wait() def long_click_id(self, id, instance=0): """ Long click *id* with *instance*=0 """ return self.d(resourceId=id, instance=0).long_click() def click_description(self, description, instance=0): """ Click *description* with *instance*=0 """ return self.d(description=description, instance=instance).long_click() def click_class(self, className, instance=0): """ Click *className* with *instance*=0 """ return self.d(className=className, instance=instance).long_click() def type_text(self, textStr, **selectors): """ type text on selectors like text=EditName """ self.d(**selectors).set_text(textStr) def press_key(self, key): """ Press Key of following value home back left right up down center menu search enter delete(or del) recent(recent apps) volume_up volume_down volume_mute camera power Examples: | Action | Argument | | Press Key | home | | Press Key | back | | Press Key | left | | Press Key | right | | Press Key | recent | | Press Key | volume_up | | Press Key | camera | """ if key.isdigit(): return self.d.press(int(key)) return self.d.press(key) def phone_sleep(self, timeout): """ android device sleep with timeout in ms, don't use for executor sleep, """ return self.d.wait(int(timeout)) def execute_command(self, cmd, block_parent_process=True): """ Execute shell *cmd* command, with block_parent_process = True If block_parent_process = False, kill_command is needed to terminal the child process Example: | Execute Command | ping -c 5 127.0.0.1 | """ if str(block_parent_process) == str(True): return subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() else: return subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) def kill_command(self, process, timeout=0): """ Kill child *process* in timeout seconds Some bugs after process teminated """ time.sleep(float(timeout)) process.terminate() def wait_for_logcat(self, log, timeout=30): """ Wait log exists in given timeout, return True if have, otherwise will return False log is your want to search, log can be a regular expression time in seconds, default value is 30 seconds Example: | Wait For Logcat | .*ActivityManager.*cmp=com.sonyericsson.album/com.sonyericsson.album.Main.* | """ start = time.time() while (time.time() - start) < int(timeout): log_proc = self.adb.cmd("logcat -d -v time") returncode = log_proc.poll() lines = log_proc.stdout.readlines() for line in lines: rlt = re.search(log, line.rstrip()) if rlt is not None: print rlt.group(0) self._result = True return True time.sleep(2) # sleep 2s to wait self._result = False return False def clear_logcat(self): """ Clear logcat, it's often used before you want to use *wait_for_logcat()* """ print "Clear logcat before test" return self.exe_adb_command("logcat -c") def click_object(self, obj): """ Click UiObject *obj* Exmaple: | ${result} | Get UI Object | text=XXX | className=xxxx | | Click Object | ${result} | """ obj.click() def click_ui(self, **selectors): """ Click selector click_selector(text="Home", resourceId = "android:id/title") for **selector, please refer *get_ui_object()* Selector supports below parameters. Refer to UiSelector java doc for detailed information. text, textContains, textMatches, textStartsWith className, classNameMatches description, descriptionContains, descriptionMatches, descriptionStartsWith checkable, checked, clickable, longClickable scrollable, enabled,focusable, focused, selected packageName, packageNameMatches resourceId, resourceIdMatches index, instance Operation for a UiObjects: click, clear_text, drag(obj).to(**selector), gesture, exists, set_text, long_click pinch.In(percent=100, steps=10), pinch.Out(percent=100, steps=100),.swipe.right(), .swipe.left(steps=10),.swipe("right", steps=20),.wait.gone(),.wait.exists() """ print "selectors:", selectors return self.d(**selectors).click() def get_ui_object(self, **selectors): """ Get UI object with *selectors* you can do anything on UiObject, like click(), long_click(),wait.exists(timeout) examples: get_ui_object(text="Home", resourceId = "android:id/title") Selector supports below parameters. Refer to UiSelector java doc for detailed information. text, textContains, textMatches, textStartsWith className, classNameMatches description, descriptionContains, descriptionMatches, descriptionStartsWith checkable, checked, clickable, longClickable scrollable, enabled,focusable, focused, selected packageName, packageNameMatches resourceId, resourceIdMatches index, instance Operation for a UiObjects: click, clear_text, drag(obj).to(**selector), gesture, exists, set_text, long_click pinch.In(percent=100, steps=10), pinch.Out(percent=100, steps=100),.swipe.right(), .swipe.left(steps=10),.swipe("right", steps=20),.wait.gone(),.wait.exists() Exmaple: | ${result} | Get UI Object | text=XXX | className=xxxx | """ self._result = self.d(**selectors) return self._result def wait_for_object_exists(self, obj, timeout=0): """ Wait for UiObject *obj* exists in *timeout*= 0 Example: | ${result} | Get UI Object | text=XXX | className=xxxx | | Wait For Object Exists | ${result} | timeout | """ self._result = obj.wait.exists(timeout=int(timeout)) return self._result def wait_for_ui_gone(self, timeout=0, **selectors): """ Wait for UiObject *obj* gone in *timeout*= 0 Example: | ${result} | Get UI Object | text=XXX | className=xxxx | | Wait For Object Gone | ${result} | timeout | """ self._result = self.d(**selectors).wait.gone(timeout=int(timeout)) return self._result def get_key_value(self, key, dictionary): """ Get key value of dictionary """ return dictionary(key) def get_tts(self, input_text, delete_file=False, **args): """ Get TTS voice mp3 from Google get_tts(input_text='tunnel snakes rule apparently', args = {'language':'en','output':'outputto.mp3'}) Robot Framework: Examples: | Action | Argument | Argument | Argument | Argument | | UiTestLib.Get TTS | Hello world | False | output=ooo.mp3 | language=en | """ print "Get text to speech: ", input_text downloaded = False if str(delete_file) == "True": if os.path.exists(args["output"]): os.remove(args["output"]) if os.path.exists(args["output"]): if os.path.getsize(args["output"]) <= 0: os.remove(args["output"]) if args["output"] is not None: if not os.path.exists(args["output"]): print "Generating mp3 file......", args["output"] downloaded = GoogleTTS.audio_extract(input_text, args) else: print "Have same local file" downloaded = True if not downloaded: print "Downloaded TTS from Google failed, trying to download from local FTP..." mp3file = open(args["output"], "w") mp3url = "ftp://cnbjlx9548/atautomation/Test-Content/Croft/" + args["output"] try: resp = urllib2.urlopen(mp3url, timeout=40) mp3file.write(resp.read()) time.sleep(0.05) except Exception, e: print e return False mp3file.close() return True
class uiAutomatorKeywords: def __init__(self): self.device = None def getDeviceInstance(self): deviceId = self.getDeviceID() if deviceId is not None: self.device = Device(deviceId) def addItemToCart(self): self.getDeviceInstance() self.openAppList() self.clickUsingText("Amazon Shopping") self.clickUsingText("Search") self.clearTheText("Search") self.setText("Search", "one plus 7 mobile") self.pressDown() self.pressEnter() self.clickUsingText("OnePlus 7 (Mirror Grey, 6GB RAM, 128GB Storage)") self.scrollAndClickAnElement("Add to Cart", "android.widget.Button") self.pressEnter() self.checkAndClickUsingText("DONE") def executeCommandOnDevice(self, command): try: output = None commandToExecute = self.__getPrefixCommand() commandToExecute += command output = subprocess.check_output(commandToExecute, shell=True) if output is not None: outputStr = output.decode('utf-8') return outputStr except Exception as e: print("Error: {}".format(e.__str__())) return None def __getPrefixCommand(self): return "adb " def getDeviceID(self): deviceId = None cmd = "devices" output = self.executeCommandOnDevice(cmd) if output is not None: for line in output.splitlines(): reObj = re.search(r'(\w+).*device\b', line) if reObj: deviceId = reObj.group(1).strip() return deviceId def openAppList(self): self.device.press.home() self.swipeUp() def getCoOrdinates(self, xPercentage, yPercentage): x = (self.device.info['displayWidth'] * xPercentage) / 100 y = (self.device.info['displayHeight'] * yPercentage) / 100 return x, y def swipeUp(self): x1, y1 = self.getCoOrdinates(50, 75) x2, y2 = self.getCoOrdinates(50, 25) self.device.swipe(x1, y1, x2, y2) def swipeDown(self): x1, y1 = self.getCoOrdinates(50, 25) x2, y2 = self.getCoOrdinates(50, 75) self.device.swipe(x1, y1, x2, y2) def scrollUp(self, speed=60): x1, y1 = self.getCoOrdinates(50, 75) x2, y2 = self.getCoOrdinates(50, 25) cmd = "shell input touchscreen swipe {} {} {} {} {}".format( x1, y1, x2, y2, speed) self.executeCommandOnDevice(cmd) def scrollDown(self, speed=60): x1, y1 = self.getCoOrdinates(50, 25) x2, y2 = self.getCoOrdinates(50, 75) cmd = "shell input touchscreen swipe {} {} {} {} {}".format( x1, y1, x2, y2, speed) self.executeCommandOnDevice(cmd) def scrollRight(self, speed=60): x1, y1 = self.getCoOrdinates(25, 50) x2, y2 = self.getCoOrdinates(75, 50) cmd = "shell input touchscreen swipe {} {} {} {} {}".format( x1, y1, x2, y2, speed) self.executeCommandOnDevice(cmd) def scrollLeft(self, speed=60): x1, y1 = self.getCoOrdinates(75, 50) x2, y2 = self.getCoOrdinates(25, 50) cmd = "shell input touchscreen swipe {} {} {} {} {}".format( x1, y1, x2, y2, speed) self.executeCommandOnDevice(cmd) def dragUp(self): x1, y1 = self.getCoOrdinates(50, 75) x2, y2 = self.getCoOrdinates(50, 25) self.device.drag(x1, y1, x2, y2) def dragDown(self): x1, y1 = self.getCoOrdinates(50, 25) x2, y2 = self.getCoOrdinates(50, 75) self.device.drag(x1, y1, x2, y2) def clickUsingText(self, textObj, className=None, instance=0): if className is None: self.device(text=textObj, instance=instance).click.wait() sleep(1) else: self.device(text=textObj, className=className, instance=instance).click.wait() def clearTheText(self, textObj, instance=0): self.device(text=textObj, instance=instance).clear_text() def setText(self, textObj, text, instance=0): self.device(text=textObj, instance=instance).set_text(text) sleep(1) def pressDown(self): self.device.press.down() sleep(1) def pressEnter(self): self.device.press.enter() sleep(1) def scrollAndClickAnElement(self, textObj, className=None, instance=0): self.getDeviceInstance() count = 0 while count <= 10: if self.isElementwithTextExists(textObj): self.clickUsingText(textObj, className, instance) print(count) # break else: self.scrollUp(500) count += 1 def isElementwithTextExists(self, textObj): if self.device(text=textObj).exists: return True return False def checkAndClickUsingText(self, textObj, instance=0): counter = 0 while counter <= 5: if self.isElementwithTextExists(textObj): self.clickUsingText(textObj, instance) sleep(2) break else: sleep(1) counter += 1 return False def recordScreen(self, filePath): cmd = "adb shell screenrecord {}".format(filePath) pid = subprocess.Popen(cmd, shell=True) if pid is not None: return pid def stopRecording(self, pid): pid.kill()