def main(): device, serialno = ViewClient.connectToDeviceOrExit(serialno=None) vc = ViewClient(device, serialno) views_dict = vc.getViewsById() print( "-------- Show the detail in the returned by the API ViewClient.getViewsById() --------" ) for key, value in views_dict.items(): print("{}:\n{}\n".format(key, unicode(value).encode("UTF-8"))) views = filter(lambda v: len(v.getId()) > 0, views_dict.values()) id_view_dict = {} for v in views: if v.getId() in id_view_dict.keys(): id_view_dict[v.getId()].append(v) else: id_view_dict[v.getId()] = [v] print("\n") print("-------- Print the id-to-view pairs --------") for key, value in id_view_dict.items(): for each in value: print("{}:\n{}\n".format(key, unicode(each).encode("UTF-8"))) vc.traverse() pass
def run(): AudioFunction.init() Logger.init(Logger.Mode.STDOUT) Adb.init() package = "com.htc.audiofunctionsdemo" activity = ".activities.MainActivity" component = package + "/" + activity device, serialno = ViewClient.connectToDeviceOrExit() vc = ViewClient(device, serialno, autodump=False) if not device.isScreenOn(): device.wake() vc.dump() import StringIO as sio so = sio.StringIO() vc.traverse(stream=so) if "lockscreen" in so.getvalue(): device.unlock() # keymap reference: # https://github.com/dtmilano/AndroidViewClient/blob/master/src/com/dtmilano/android/adb/androidkeymap.py device.press("HOME") time.sleep(1) device.startActivity(component=component) time.sleep(1) playback_task_run(device) record_task_run(device, serialno) AudioFunction.finalize() Logger.finalize()
def get_state(self): vc = ViewClient(self.device, self.serialno) so = sio.StringIO() vc.traverse(stream=so) states = [state for state in GoogleMusicApp.State.ALL_STATES if state["check"](so.getvalue())] if len(states) > 1: self.push_dump("get_state returns more than one states: [{}]".format( \ ", ".join(map(lambda state: "'{}'".format(state["name"]), states)) \ )) if len(states) > 0: return states[0]["name"] return GoogleMusicApp.State.UNKNOWN
def wake_device(device, serialno): if device.isScreenOn(): return device.wake() vc = ViewClient(device, serialno, autodump=False) try: vc.dump(sleep=0) so = sio.StringIO() vc.traverse(stream=so) if "lockscreen" in so.getvalue(): device.unlock() except: pass
def get_current_song(self): vc = ViewClient(self.handler.device, self.handler.serialno) so = sio.StringIO() vc.traverse(stream=so) line = [line for line in so.getvalue().splitlines() if GoogleMusicApp.CONTROL_PANEL_TRACKNAME_KEY in line] line = line[0] if len(line) > 0 else None if line: name = utf8str(line.split(GoogleMusicApp.CONTROL_PANEL_TRACKNAME_KEY)[-1].strip()) for playcard_title, info in self.handler.cache["playcard"].items(): if "songs" in info.keys() and name in info["songs"].keys(): song = dict(info["songs"][name]) song["name"] = name song["playcard"] = playcard_title return song return None
def testViewClient_oneDevice_TwoViewClients(self): localPort1 = 9005 remotePort1 = 9006 print "Conencting to", remotePort1 vc1 = ViewClient(device=ViewClientTest.device1, serialno=ViewClientTest.serialno1, localport=localPort1, remoteport=remotePort1, autodump=True) self.assertTrue(vc1.getRoot() != None) vc1.traverse() localPort2 = 9007 remotePort2 = 9008 print "Conencting to", remotePort2 vc2 = ViewClient(device=ViewClientTest.device2, serialno=ViewClientTest.serialno2, localport=localPort2, remoteport=remotePort2, autodump=True) self.assertTrue(vc2.getRoot() != None) vc2.traverse()
pass from com.dtmilano.android.viewclient import ViewClient, View from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice device, serialno = ViewClient.connectToDeviceOrExit() DEBUG = True FLAG_ACTIVITY_NEW_TASK = 0x10000000 # We are not using Settings as the bug describes because there's no WiFi dialog in emulator componentName = 'com.android.settings/.Settings' device.startActivity(component=componentName, flags=FLAG_ACTIVITY_NEW_TASK) MonkeyRunner.sleep(3) vc = ViewClient(device=device, serialno=serialno) if DEBUG: vc.traverse(transform=ViewClient.TRAVERSE_CIT) sound = vc.findViewWithText('Sound') if sound: sound.touch() vc.dump() phoneRingtone = vc.findViewWithText('Phone ringtone') if phoneRingtone: phoneRingtone.touch() vc.dump() vespa = vc.findViewWithText('Vespa') if vespa: vespa.touch() MonkeyRunner.sleep(1) ok = vc.findViewById('id/button1') if ok: ok.touch()
#! /usr/bin/env python ''' Copyright (C) 2014 Diego Torres Milano Created on Apr 24, 2014 @author: diego ''' from com.dtmilano.android.viewclient import ViewClient kwargs1 = {'verbose': True, 'ignoresecuredevice': True} kwargs2 = {'startviewserver': True, 'forceviewserveruse': True, 'autodump': False, 'ignoreuiautomatorkilled': True} vc = ViewClient(*ViewClient.connectToDeviceOrExit(**kwargs1), **kwargs2) windows = vc.list() for wId in windows.keys(): print ">>> window=", wId, windows[wId] vc.dump(window=wId) vc.traverse(transform=ViewClient.TRAVERSE_CIT, indent=" ")
import re import sys import os # This must be imported before MonkeyRunner and MonkeyDevice, # otherwise the import fails. # PyDev sets PYTHONPATH, use it try: for p in os.environ['PYTHONPATH'].split(':'): if not p in sys.path: sys.path.append(p) except: pass try: sys.path.append(os.path.join(os.environ['ANDROID_VIEW_CLIENT_HOME'], 'src')) except: pass from com.dtmilano.android.viewclient import ViewClient from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice device, serialno = ViewClient.connectToDeviceOrExit() vc = ViewClient(device, serialno) ''' % date.today() vc.traverse(transform=transform)
except: pass from com.dtmilano.android.viewclient import ViewClient, View device, serialno = ViewClient.connectToDeviceOrExit() DEBUG = True FLAG_ACTIVITY_NEW_TASK = 0x10000000 # We are not using Settings as the bug describes because there's no WiFi dialog in emulator componentName = 'com.android.settings/.Settings' device.startActivity(component=componentName, flags=FLAG_ACTIVITY_NEW_TASK) ViewClient.sleep(3) vc = ViewClient(device=device, serialno=serialno) if DEBUG: vc.traverse(transform=ViewClient.TRAVERSE_CIT) sound = vc.findViewWithText('Sound') if sound: sound.touch() vc.dump() phoneRingtone = vc.findViewWithText('Phone ringtone') if phoneRingtone: phoneRingtone.touch() vc.dump() vespa = vc.findViewWithText('Vespa') if vespa: vespa.touch() ViewClient.sleep(1) ok = vc.findViewById('id/button1') if ok: ok.touch()
def walk_through(self): if not self.to_top(): Logger.log("GoogleMusicApp", "walk_through failed: unable to go to top activity") self.cache_init = False return False # Get the playcard titles vc = ViewClient(self.device, self.serialno) self.cache_init = True container_key = GoogleMusicApp.CONTAINER_KEY container = [v for v in vc.getViewsById().values() if v.getId() == container_key] container = container[0] if len(container) > 0 else None if container: self.cache["screen-info"] = container.getBounds()[1] self.push_dump("screen-info: {}".format(self.cache["screen-info"])) so = sio.StringIO() vc.traverse(stream=so) lines = so.getvalue().splitlines() play_card_key = GoogleMusicApp.PLAY_CARD_KEY playcards_idices = [idx for idx, line in enumerate(lines) if play_card_key in line] playcards_idices.append(len(lines)) playcards_titles = [] last_idx = playcards_idices[0] li_title_key = GoogleMusicApp.LI_TITLE_KEY for idx in playcards_idices[1:]: li_title_texts = [line for line in lines[last_idx:idx] if li_title_key in line] last_idx = idx if len(li_title_texts) != 1: self.push_dump("li_title_texts has length {}".format(len(li_title_texts))) playcards_titles.append(utf8str(li_title_texts[0].split(li_title_key)[-1].strip())) self.push_dump("playcards_titles.append('{}')".format(playcards_titles[-1])) # Get the track list of each playcard views = [v for v in vc.getViewsById().values() if v.getId() == li_title_key and utf8str(v.getText()) in playcards_titles] self.cache["playcard"] = dict( \ map(lambda v: (utf8str(v.getText()), { "position": v.getCenter() }), views) ) map(lambda v: self.push_dump("view: {}".format(utf8str(v))), views) map(lambda title: self.push_dump("playcard title: '{}'".format(title)), self.cache["playcard"].keys()) if len(views) == 0: self.cache_init = False return False self.cache["shuffle_key"] = playcards_titles[0] self.push_dump("get the shuffle keyword '{}'".format(self.cache["shuffle_key"])) self.touch_playcard(self.cache["shuffle_key"]) time.sleep(1) retry_count = 3 while retry_count > 0: vc.dump() play_pause_header_key = GoogleMusicApp.PLAY_PAUSE_HEADER_KEY play_pause_btn_view = [v for v in vc.getViewsById().values() if v.getId() == play_pause_header_key] play_pause_btn_view = play_pause_btn_view[0] if len(play_pause_btn_view) > 0 else None if play_pause_btn_view: play_desc = utf8str(play_pause_btn_view.getContentDescription()) self.check_play_status = lambda desc: desc == play_desc self.cache["play_pause_btn"] = { "position": play_pause_btn_view.getCenter(), "desc_feat": play_desc } art_pager_key = GoogleMusicApp.ART_PAGER_KEY art_pager_view = [v for v in vc.getViewsById().values() if v.getId() == art_pager_key] art_pager_view = art_pager_view[0] if len(art_pager_view) > 0 else None if not art_pager_view: retry_count -= 1 continue self.cache["art_pager_view"] = { "position": art_pager_view.getCenter() } play_pause_btn_view.touch() break else: self.push_dump("cannot find the play/pause button, retry: {}".format(retry_count)) retry_count -= 1 if retry_count == 0: return False for li_title in self.cache["playcard"].keys(): if li_title == self.cache["shuffle_key"]: continue self.push_dump("now fetching information in the playcard '{}'".format(li_title)) if self.touch_playcard(li_title=li_title): time.sleep(1) self.cache["playcard"][li_title]["songs"] = self._fetch_songs() self.to_top() # Get the information of the control panel retry_count = 3 while self.get_state() != GoogleMusicApp.State.CONTROL_PANEL and retry_count > 0: self.device.touch(*self.cache["art_pager_view"]["position"]) retry_count -= 1 if retry_count == 0 and self.get_state() != GoogleMusicApp.State.CONTROL_PANEL: self.to_top() time.sleep(5) self.touch_playcard(self.cache["shuffle_key"]) time.sleep(2) self.device.touch(*self.cache["play_pause_btn"]["position"]) time.sleep(2) self.device.touch(*self.cache["art_pager_view"]["position"]) time.sleep(2) if self.get_state() != GoogleMusicApp.State.CONTROL_PANEL: self.push_dump("cannot get the information of the control panel") self.cache_init = False return False def find_view_position(vc, res_id): v = [v for v in vc.getViewsById().values() if v.getId() == res_id] if len(v) == 0: return ((-1, -1), (-1, -1)), (-1, -1) return v[0].getBounds(), v[0].getCenter() vc.dump() progress_bounds, progress_pos = find_view_position(vc, GoogleMusicApp.CONTROL_PANEL_PROGRESS_KEY) self.cache["control_panel"] = { "progress": { "position": progress_pos, "xbounds": [progress_bounds[0][0], progress_bounds[1][0]] }, "prev": { "position": find_view_position(vc, GoogleMusicApp.CONTROL_PANEL_PREV_KEY)[1] }, "next": { "position": find_view_position(vc, GoogleMusicApp.CONTROL_PANEL_NEXT_KEY)[1] }, "play_pause": { "position": find_view_position(vc, GoogleMusicApp.CONTROL_PANEL_PLAY_PAUSE_KEY)[1] } } self.control_panel = GMControlPanel(self) self.push_dump("successfully walked through, now back to top") self.to_top() self.cache_init = True return True
def loadScreenshots(): # Read all chats in list device, serialno = ViewClient.connectToDeviceOrExit() device.press('KEYCODE_HOME') device.startActivity(component=component) ViewClient.sleep(TOUCH_LONG_SLEEP) vc = ViewClient(device, serialno, autodump=True) putMainScreen(vc) toStart(vc) ##coments if necessary continue a extraction vc.dump() new_chats = True while new_chats: #check screen changes (in chat list) after dragging # track the chat list beginning. brute_chatList = vc.findViewsWithAttribute('class', 'android.view.ViewGroup') if brute_chatList[0] is None: logging.error('Cant go back to Facebook Home') quit() # capture new chats in screen list chatList = [] new_chats = False for c in brute_chatList[0].children: if len(c.getText()) > 0 and c.getText( ) != 'Online' and not c.getContentDescription() in visitedChats: print c.getContentDescription().encode('utf-8') chatList.append(c) new_chats = True print "new Chats:(", len(chatList), ")", 'total ', len(visitedChats) # process new chats for chat in chatList: print '->' + chat.getContentDescription().encode( 'utf-8'), chat.getTag(), chat.getUniqueId() path = '' if isinstance(chat.getContentDescription(), unicode): path = unicode( extraction_path + '/' + norm_unicode_filename(chat.getContentDescription())) if isinstance(chat.getContentDescription(), str): path = extraction_path + '/' + werkzeug.utils.secure_filename( chat.getContentDescription().encode('utf-8')) os.mkdir(path, 0777) device, serialno = ViewClient.connectToDeviceOrExit() vc = ViewClient(device, serialno) chat.touch() #print 'touching...' if vc.isKeyboardShown(): device.press('KEYCODE_BACK') root = vc.findViewsWithAttribute('class', 'android.view.ViewGroup') #print "Grupo:", len(root), root[0].getContentDescription(), root[0].getText() vc = ViewClient(device, serialno) # snapshot screen screenshot_count = 1 before_dump = '' strScreen = StringIO.StringIO() vc.traverse(transform=ViewClient.TRAVERSE_CITPS, stream=strScreen) after_dump = strScreen.getvalue() while before_dump != after_dump: #check screen changes (in msgs list) after dragging before_dump = after_dump print 'screenshot', screenshot_count device.takeSnapshot().save( path + '/screenshot_' + str(screenshot_count) + ".png", 'PNG') device, serialno = ViewClient.connectToDeviceOrExit() vc = ViewClient(device, serialno) #print 'connected?',device.checkConnected() device.dragDip((169.0, 297.0), (173.0, 600.0), 1000, 20, 0) attemptCount = 0 while attemptCount < 5: try: attemptCount = attemptCount + 1 vc = ViewClient(device, serialno) break except: print 'Houston...we have a problem (BEEP) - small drag tilt' device.dragDip((169.0, 297.0), (173.0, 310.0), 1000, 20, 0) if attemptCount == 5: print 'ERROR' exit(1) strScreen = StringIO.StringIO() vc.traverse(transform=ViewClient.TRAVERSE_CITPS, stream=strScreen) after_dump = strScreen.getvalue() screenshot_count = screenshot_count + 1 visitedChats.append(chat.getContentDescription()) putMainScreen(vc) #device.press('KEYCODE_BACK'); # drag chat list device.dragDip((173.0, 560.0), (169.0, 150.0), 1000, 20, 0) vc = ViewClient(device, serialno) #Am i in FBM home? print 'put main screen' putMainScreen(vc) print 'Total chats:', len(visitedChats)
#! /usr/bin/env python import sys import os try: sys.path.insert( 0, os.path.join(os.environ['ANDROID_VIEW_CLIENT_HOME'], 'src')) except: pass from com.dtmilano.android.viewclient import ViewClient from com.dtmilano.android.viewclient import View vc = ViewClient(*ViewClient.connectToDeviceOrExit()) vc.traverse()
options[SCREEN_GLARE] = True elif o in ['h', USE_UIAUTOMATOR_HELPER]: kwargs2[ViewClientOptions.USE_UIAUTOMATOR_HELPER] = True elif o in ['D', DO_NOT_DUMP_VIEWS]: options[DO_NOT_DUMP_VIEWS] = True transform = MAP[o] elif o in ['X', DEBUG]: kwargs2[ViewClientOptions.DEBUG] = debugArgsToDict(a) else: transform = MAP[o] if options[DO_NOT_DUMP_VIEWS]: transform = MAP[DO_NOT_DUMP_VIEWS] vc = ViewClient(*ViewClient.connectToDeviceOrExit(**kwargs1), **kwargs2) if options[SAVE_SCREENSHOT]: vc.device.reconnect = True #(not options[DO_NOT_DUMP_VIEWS]) ext = os.path.splitext(options[SAVE_SCREENSHOT])[1][1:].upper() _format = ext if ext == 'JPG': _format = 'JPEG' vc.writeImageToFile(options[SAVE_SCREENSHOT], _format=_format, deviceart=options[DEVICE_ART], dropshadow=options[DROP_SHADOW], screenglare=options[SCREEN_GLARE]) if not options[DO_NOT_DUMP_VIEWS] or options[SAVE_VIEW_SCREENSHOTS]: vc.dump(window=options[WINDOW]) ViewClient.imageDirectory = options[SAVE_VIEW_SCREENSHOTS] vc.traverse(transform=transform) if kwargs2[ViewClientOptions.USE_UIAUTOMATOR_HELPER]: try: vc.uiAutomatorHelper.quit() except: pass
class YkspTestCase(unittest.TestCase): package = None serial = None dirRoot = None logsFilename = None screenshotFolder = None screendumpFolder = None screenCount = 0 def setUp(self): # Connnect to device self.device, self.serialno = ViewClient.connectToDeviceOrExit(serialno=YkspTestCase.serial) # Wake device self.device.wake() # Create ViewClient instance self.vc = ViewClient(self.device, self.serialno, autodump=False) def tearDown(self): # Force-stop the app self.device.shell('am force-stop %s' % YkspTestCase.package) def launchApp(self, package=None): ''' Launches an app as if from the launcher. @type package: str @param package: An optional parameter to specify an application to launch by its package name. If not provided, the application package name provided in the application manifest is used. ''' if package is None: package = YkspTestCase.package # Launch application only if the package is installed if self.device.shell('pm path %s' % package): self.device.shell('monkey -p %s -c android.intent.category.LAUNCHER 1' % package) else: self.fail('Failed to launch application. %s is not installed on this device' % package) def refreshScreen(self, sleep=1): ''' Updates the view tree. This method or saveScreen() must be called after each screen transition to keep the view tree in sync with the device screen. @type sleep: float @param sleep: An optional parameter to indicate the time to sleep before refreshing the screen. Defaults to one second. ''' self.vc.dump(window=-1, sleep=sleep) def saveScreen(self, tag=None, sleep=1): ''' Updates the view tree and saves to disk the screenshot and screendump of the device screen. This method or refreshScreen() must be called after each screen transition to keep the view tree in sync with the device screen. @type tag: str @param tag: The tag for this screen. This is appended to the filename. @type sleep: float @param sleep: An optional parameter to indicate the time to sleep before saving the screen. Defaults to one second. ''' if sleep > 0: self.vc.sleep(sleep) filename = YkspTestCase.screenCount if tag: filename = '%s-%s' % (filename, tag) # Take a screenshot and save self.device.takeSnapshot(reconnect=True).save('%s/%s/%s.png' % (YkspTestCase.dirRoot, YkspTestCase.screenshotFolder, filename), 'PNG') # Take a screendump and save screendump = self.vc.dump(window=-1, sleep=0) screendumpStream = open('%s/%s/%s.txt' % (YkspTestCase.dirRoot, YkspTestCase.screendumpFolder, filename), 'w') self.vc.traverse(transform=self.vc.TRAVERSE_CITPS, stream=screendumpStream) screendumpStream.close() YkspTestCase.screenCount += 1 @staticmethod def parseArgs(argv): try: opts, args = getopt.getopt(argv[1:], 'hp:s:r:l:m:n:', ['help', 'package=', 'serial=', 'root=', 'logs=', 'screenshots=', 'screendumps=']) except getopt.GetoptError: YkspTestCase.usage(2) for opt, arg in opts: if opt in ('-h', '--help'): YkspTestCase.usage(2) elif opt in ('-p', '--package'): YkspTestCase.package = arg argv.remove(opt) argv.remove(arg) elif opt in ('-s', '--serial'): YkspTestCase.serial = arg argv.remove(opt) argv.remove(arg) elif opt in ('-r', '--root'): YkspTestCase.dirRoot = arg argv.remove(opt) argv.remove(arg) elif opt in ('-l', '--logs'): YkspTestCase.logsFilename = arg argv.remove(opt) argv.remove(arg) elif opt in ('-m', '--screenshots'): YkspTestCase.screenshotFolder = arg argv.remove(opt) argv.remove(arg) elif opt in ('-n', '--screendumps'): YkspTestCase.screendumpFolder = arg argv.remove(opt) argv.remove(arg) if YkspTestCase.package is None: print '\nError:' print '--package must be specified' YkspTestCase.usage(2) if YkspTestCase.serial is None: print '\nError:' print '--serial must be specified' YkspTestCase.usage(2) if YkspTestCase.dirRoot is None: print '\nError:' print '--root must be specified' YkspTestCase.usage(2) if YkspTestCase.screenshotFolder is None: print '\nError:' print '--screenshots must be specified' YkspTestCase.usage(2) if YkspTestCase.screendumpFolder is None: print '\nError:' print '--screendumps must be specified' YkspTestCase.usage(2) if os.path.isdir(YkspTestCase.dirRoot) is False: print '\nError:' print '--root specifies an invalid directory' YkspTestCase.usage(2) @staticmethod def usage(exitVal=0): print '\nUsage:' print '-h, --help OPTIONAL print this help and exit' print '-p, --package <package> REQUIRED specify the package name of the application' print '-s, --serial <serial> REQUIRED specify the serial number of the device to run this test case' print '-r, --root <dir> REQUIRED specify the root directory to save the results of this test case' print '-l, --logs <dir> OPTIONAL specify the filename to save the PyUnit logs' print '-m, --screenshots <folder> REQUIRED specify the folder name to save the screenshots' print '-n, --screendumps <folder> REQUIRED specify the folder name to save the screendumps' sys.exit(exitVal) @staticmethod def main(argv): YkspTestCase.parseArgs(argv) # Create subdirectories dirScreenshot = '%s/%s' % (YkspTestCase.dirRoot, YkspTestCase.screenshotFolder) if os.path.isdir(dirScreenshot) is False: os.mkdir(dirScreenshot) dirScreendump = '%s/%s' % (YkspTestCase.dirRoot, YkspTestCase.screendumpFolder) if os.path.isdir(dirScreendump) is False: os.mkdir(dirScreendump) # Configure logging and execute test case if YkspTestCase.logsFilename: logsStream = open('%s/%s' % (YkspTestCase.dirRoot, YkspTestCase.logsFilename), 'w') runner = unittest.TextTestRunner(stream=logsStream, verbosity=2) unittest.main(testRunner=runner) else: unittest.main()