|
17 | 17 | @author: diego |
18 | 18 | ''' |
19 | 19 |
|
20 | | -__version__ = '2.2' |
| 20 | +__version__ = '2.3' |
21 | 21 |
|
22 | 22 | import sys |
23 | 23 | import subprocess |
|
31 | 31 | import warnings |
32 | 32 | from com.android.monkeyrunner import MonkeyDevice, MonkeyRunner |
33 | 33 |
|
34 | | -DEBUG = False |
| 34 | +DEBUG = True |
35 | 35 | DEBUG_DEVICE = DEBUG and True |
36 | | -DEBUG_RECEIVED = DEBUG and False |
| 36 | +DEBUG_RECEIVED = DEBUG and True |
37 | 37 | DEBUG_TREE = DEBUG and False |
38 | 38 | DEBUG_GETATTR = DEBUG and False |
39 | 39 | DEBUG_COORDS = DEBUG and False |
|
53 | 53 |
|
54 | 54 | USE_MONKEYRUNNER_TO_GET_BUILD_PROPERTIES = True |
55 | 55 |
|
| 56 | +USE_UI_AUTOMATOR = False |
| 57 | + |
56 | 58 | SKIP_CERTAIN_CLASSES_IN_GET_XY_ENABLED = False |
57 | 59 | ''' Skips some classes related with the Action Bar and the PhoneWindow$DecorView in the |
58 | 60 | coordinates calculation |
59 | 61 | @see: L{View.getXY()} ''' |
60 | 62 |
|
61 | 63 | # some device properties |
62 | | -VERSION_SDK_PROPERTY = "version.sdk" |
| 64 | +VERSION_SDK_PROPERTY = 'version.sdk' |
63 | 65 |
|
64 | 66 | # some constants for the attributes |
65 | 67 | TEXT_PROPERTY = 'text:mText' |
|
68 | 70 | GET_VISIBILITY_PROPERTY = 'getVisibility()' |
69 | 71 | LAYOUT_TOP_MARGIN_PROPERTY = 'layout:layout_topMargin' |
70 | 72 |
|
71 | | -VERSION_SDK_PROPERTY = 'version.sdk' |
72 | | - |
73 | 73 | # visibility |
74 | 74 | VISIBLE = 0x0 |
75 | 75 | INVISIBLE = 0x4 |
@@ -746,22 +746,6 @@ def __init__(self, device, serialno, adb=None, autodump=True, localport=VIEW_SER |
746 | 746 | else: |
747 | 747 | adb = ViewClient.__obtainAdbPath() |
748 | 748 |
|
749 | | - if startviewserver: |
750 | | - if not self.serviceResponse(device.shell('service call window 3')): |
751 | | - try: |
752 | | - self.assertServiceResponse(device.shell('service call window 1 i32 %d' % |
753 | | - remoteport)) |
754 | | - except: |
755 | | - raise Exception('Cannot start View server.\n' |
756 | | - 'This only works on emulator and devices running developer versions.\n' |
757 | | - 'Does hierarchyviewer work on your device ?') |
758 | | - |
759 | | - self.localPort = localport |
760 | | - self.remotePort = remoteport |
761 | | - # FIXME: it seems there's no way of obtaining the serialno from the MonkeyDevice |
762 | | - subprocess.check_call([adb, '-s', self.serialno, 'forward', 'tcp:%d' % self.localPort, |
763 | | - 'tcp:%d' % self.remotePort]) |
764 | | - |
765 | 749 | self.root = None |
766 | 750 | ''' The root node ''' |
767 | 751 | self.viewsById = {} |
@@ -794,17 +778,30 @@ def __init__(self, device, serialno, adb=None, autodump=True, localport=VIEW_SER |
794 | 778 | if prop == VERSION_SDK_PROPERTY: |
795 | 779 | # we expect it to be an int |
796 | 780 | self.build[prop] = int(self.build[prop] if self.build[prop] else -1) |
797 | | - |
798 | | - try: |
799 | | - self.build[prop] = device.getProperty('build.' + prop) |
800 | | - if prop == VERSION_SDK_PROPERTY: |
801 | | - self.build[prop] = int(self.build[prop]) |
802 | | - except: |
803 | | - self.build[prop] = -1 |
804 | 781 |
|
805 | 782 | if self.build[VERSION_SDK_PROPERTY] > 0 and self.build[VERSION_SDK_PROPERTY] <= 10: # gingerbread 2.3.3 |
806 | 783 | global TEXT_PROPERTY |
807 | 784 | TEXT_PROPERTY = TEXT_PROPERTY_API_10 |
| 785 | + elif self.build[VERSION_SDK_PROPERTY] > 16: # jelly bean 4.2 |
| 786 | + global USE_UI_AUTOMATOR |
| 787 | + USE_UI_AUTOMATOR = True |
| 788 | + |
| 789 | + if not USE_UI_AUTOMATOR: |
| 790 | + if startviewserver: |
| 791 | + if not self.serviceResponse(device.shell('service call window 3')): |
| 792 | + try: |
| 793 | + self.assertServiceResponse(device.shell('service call window 1 i32 %d' % |
| 794 | + remoteport)) |
| 795 | + except: |
| 796 | + raise Exception('Cannot start View server.\n' |
| 797 | + 'This only works on emulator and devices running developer versions.\n' |
| 798 | + 'Does hierarchyviewer work on your device ?') |
| 799 | + |
| 800 | + self.localPort = localport |
| 801 | + self.remotePort = remoteport |
| 802 | + # FIXME: it seems there's no way of obtaining the serialno from the MonkeyDevice |
| 803 | + subprocess.check_call([adb, '-s', self.serialno, 'forward', 'tcp:%d' % self.localPort, |
| 804 | + 'tcp:%d' % self.remotePort]) |
808 | 805 |
|
809 | 806 | if autodump: |
810 | 807 | self.dump() |
@@ -1058,6 +1055,23 @@ def setViews(self, received): |
1058 | 1055 | print >>sys.stderr, "there are %d views in this dump" % len(self.views) |
1059 | 1056 | self.__parseTree(received.split("\n")) |
1060 | 1057 |
|
| 1058 | + def setViewsFromUiAutomatorDump(self, received): |
| 1059 | + ''' |
| 1060 | + Sets L{self.views} to the received value parsing the received XML. |
| 1061 | + |
| 1062 | + @type received: str |
| 1063 | + @param received: the string received from the I{UI Automator} |
| 1064 | + ''' |
| 1065 | + |
| 1066 | + if not received or received == "": |
| 1067 | + raise ValueError("received is empty") |
| 1068 | + self.views = [] |
| 1069 | + ''' The list of Views represented as C{str} obtained after splitting it into lines after being received from the server. Done by L{self.setViews()}. ''' |
| 1070 | + if DEBUG: |
| 1071 | + print >>sys.stderr, "there are %d views in this dump" % len(self.views) |
| 1072 | + self.__parseTreeFromUiAutomatorDump(self.received) |
| 1073 | + |
| 1074 | + |
1061 | 1075 | def __splitAttrs(self, strArgs, addViewToViewsById=False): |
1062 | 1076 | ''' |
1063 | 1077 | Splits the C{View} attributes in C{strArgs} and optionally adds the view id to the C{viewsById} list. |
@@ -1202,7 +1216,9 @@ def __parseTree(self, receivedLines): |
1202 | 1216 | parent.add(child) |
1203 | 1217 | treeLevel = newLevel |
1204 | 1218 | lastView = child |
1205 | | - |
| 1219 | + |
| 1220 | + def __parseTreeFromUiAutomatorDump(self, receivedXml): |
| 1221 | + raise RuntimeError("NOT IMPLEMENTED YET!") |
1206 | 1222 |
|
1207 | 1223 | def getRoot(self): |
1208 | 1224 | ''' |
@@ -1256,31 +1272,45 @@ def dump(self, windowId=-1, sleep=1): |
1256 | 1272 |
|
1257 | 1273 | if sleep > 0: |
1258 | 1274 | MonkeyRunner.sleep(sleep) |
1259 | | - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
1260 | | - try: |
1261 | | - s.connect((VIEW_SERVER_HOST, self.localPort)) |
1262 | | - except socket.error, ex: |
1263 | | - raise RuntimeError("ERROR: Connecting to %s:%d: %s" % (VIEW_SERVER_HOST, self.localPort, ex)) |
1264 | | - s.send('dump %d\r\n' % windowId) |
1265 | | - received = "" |
1266 | | - doneRE = re.compile("DONE") |
1267 | | - while True: |
1268 | | - received += s.recv(1024) |
1269 | | - if doneRE.search(received[-7:]): |
1270 | | - break |
1271 | | - |
1272 | | - s.close() |
1273 | | - if DEBUG: |
1274 | | - self.received = received |
1275 | | - if DEBUG_RECEIVED: |
1276 | | - print >>sys.stderr, "received %d chars" % len(received) |
1277 | | - print >>sys.stderr |
1278 | | - print >>sys.stderr, received |
1279 | | - print >>sys.stderr |
1280 | | - self.setViews(received) |
1281 | | - |
1282 | | - if DEBUG_TREE: |
1283 | | - self.traverse(self.root) |
| 1275 | + |
| 1276 | + if USE_UI_AUTOMATOR: |
| 1277 | + if not re.search('dumped', self.device.shell('uiautomator dump /mnt/sdcard/window_dump.xml')): |
| 1278 | + raise RuntimeError('ERROR: Getting UIAutomator dump') |
| 1279 | + received = self.device.shell('cat /mnt/sdcard/window_dump.xml') |
| 1280 | + if DEBUG: |
| 1281 | + self.received = received.encode('ascii', 'ignore') |
| 1282 | + if DEBUG_RECEIVED: |
| 1283 | + print >>sys.stderr, "received %d chars" % len(received) |
| 1284 | + print >>sys.stderr |
| 1285 | + print >>sys.stderr, self.received |
| 1286 | + print >>sys.stderr |
| 1287 | + self.setViewsFromUiAutomatorDump(self.received) |
| 1288 | + else: |
| 1289 | + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| 1290 | + try: |
| 1291 | + s.connect((VIEW_SERVER_HOST, self.localPort)) |
| 1292 | + except socket.error, ex: |
| 1293 | + raise RuntimeError("ERROR: Connecting to %s:%d: %s" % (VIEW_SERVER_HOST, self.localPort, ex)) |
| 1294 | + s.send('dump %d\r\n' % windowId) |
| 1295 | + received = "" |
| 1296 | + doneRE = re.compile("DONE") |
| 1297 | + while True: |
| 1298 | + received += s.recv(1024) |
| 1299 | + if doneRE.search(received[-7:]): |
| 1300 | + break |
| 1301 | + |
| 1302 | + s.close() |
| 1303 | + if DEBUG: |
| 1304 | + self.received = received |
| 1305 | + if DEBUG_RECEIVED: |
| 1306 | + print >>sys.stderr, "received %d chars" % len(received) |
| 1307 | + print >>sys.stderr |
| 1308 | + print >>sys.stderr, received |
| 1309 | + print >>sys.stderr |
| 1310 | + self.setViews(received) |
| 1311 | + |
| 1312 | + if DEBUG_TREE: |
| 1313 | + self.traverse(self.root) |
1284 | 1314 |
|
1285 | 1315 | return self.views |
1286 | 1316 |
|
|
0 commit comments