Skip to content

Commit 8ec7421

Browse files
committed
Added support for UiAutomator dump when supported
1 parent 2b0d36f commit 8ec7421

1 file changed

Lines changed: 85 additions & 55 deletions

File tree

AndroidViewClient/src/com/dtmilano/android/viewclient.py

Lines changed: 85 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
@author: diego
1818
'''
1919

20-
__version__ = '2.2'
20+
__version__ = '2.3'
2121

2222
import sys
2323
import subprocess
@@ -31,9 +31,9 @@
3131
import warnings
3232
from com.android.monkeyrunner import MonkeyDevice, MonkeyRunner
3333

34-
DEBUG = False
34+
DEBUG = True
3535
DEBUG_DEVICE = DEBUG and True
36-
DEBUG_RECEIVED = DEBUG and False
36+
DEBUG_RECEIVED = DEBUG and True
3737
DEBUG_TREE = DEBUG and False
3838
DEBUG_GETATTR = DEBUG and False
3939
DEBUG_COORDS = DEBUG and False
@@ -53,13 +53,15 @@
5353

5454
USE_MONKEYRUNNER_TO_GET_BUILD_PROPERTIES = True
5555

56+
USE_UI_AUTOMATOR = False
57+
5658
SKIP_CERTAIN_CLASSES_IN_GET_XY_ENABLED = False
5759
''' Skips some classes related with the Action Bar and the PhoneWindow$DecorView in the
5860
coordinates calculation
5961
@see: L{View.getXY()} '''
6062

6163
# some device properties
62-
VERSION_SDK_PROPERTY = "version.sdk"
64+
VERSION_SDK_PROPERTY = 'version.sdk'
6365

6466
# some constants for the attributes
6567
TEXT_PROPERTY = 'text:mText'
@@ -68,8 +70,6 @@
6870
GET_VISIBILITY_PROPERTY = 'getVisibility()'
6971
LAYOUT_TOP_MARGIN_PROPERTY = 'layout:layout_topMargin'
7072

71-
VERSION_SDK_PROPERTY = 'version.sdk'
72-
7373
# visibility
7474
VISIBLE = 0x0
7575
INVISIBLE = 0x4
@@ -746,22 +746,6 @@ def __init__(self, device, serialno, adb=None, autodump=True, localport=VIEW_SER
746746
else:
747747
adb = ViewClient.__obtainAdbPath()
748748

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-
765749
self.root = None
766750
''' The root node '''
767751
self.viewsById = {}
@@ -794,17 +778,30 @@ def __init__(self, device, serialno, adb=None, autodump=True, localport=VIEW_SER
794778
if prop == VERSION_SDK_PROPERTY:
795779
# we expect it to be an int
796780
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
804781

805782
if self.build[VERSION_SDK_PROPERTY] > 0 and self.build[VERSION_SDK_PROPERTY] <= 10: # gingerbread 2.3.3
806783
global TEXT_PROPERTY
807784
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])
808805

809806
if autodump:
810807
self.dump()
@@ -1058,6 +1055,23 @@ def setViews(self, received):
10581055
print >>sys.stderr, "there are %d views in this dump" % len(self.views)
10591056
self.__parseTree(received.split("\n"))
10601057

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+
10611075
def __splitAttrs(self, strArgs, addViewToViewsById=False):
10621076
'''
10631077
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):
12021216
parent.add(child)
12031217
treeLevel = newLevel
12041218
lastView = child
1205-
1219+
1220+
def __parseTreeFromUiAutomatorDump(self, receivedXml):
1221+
raise RuntimeError("NOT IMPLEMENTED YET!")
12061222

12071223
def getRoot(self):
12081224
'''
@@ -1256,31 +1272,45 @@ def dump(self, windowId=-1, sleep=1):
12561272

12571273
if sleep > 0:
12581274
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)
12841314

12851315
return self.views
12861316

0 commit comments

Comments
 (0)