11'''
2+ Copyright (C) 2012-2013 Diego Torres Milano
23Created on Dec 1, 2012
34
4- @author: diego
5+ Licensed under the Apache License, Version 2.0 (the "License");
6+ you may not use this file except in compliance with the License.
7+ You may obtain a copy of the License at
8+
9+ http://www.apache.org/licenses/LICENSE-2.0
10+
11+ Unless required by applicable law or agreed to in writing, software
12+ distributed under the License is distributed on an "AS IS" BASIS,
13+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+ See the License for the specific language governing permissions and
15+ limitations under the License.
16+
17+ @author: Diego Torres Milano
518'''
19+
20+ __version__ = '4.2.0'
21+
622import sys
723import socket
824import time
@@ -104,7 +120,7 @@ def __send(self, msg, checkok=True, reconnect=False):
104120 self .__setTransport ()
105121 else :
106122 self .checkConnected ()
107- self .socket .send ('%04x %s' % (len (msg ), msg ))
123+ self .socket .send ('%04X %s' % (len (msg ), msg ))
108124 if checkok :
109125 self .__checkOk ()
110126 if reconnect :
@@ -113,13 +129,23 @@ def __send(self, msg, checkok=True, reconnect=False):
113129 self .__connect ()
114130 self .__setTransport ()
115131
116- def __receive (self ):
132+ def __receive (self , nob = None ):
117133 if DEBUG :
118134 print >> sys .stderr , "__receive()"
119135 self .checkConnected ()
120- n = int (self .socket .recv (4 ), 16 )
121- recv = self .socket .recv (n )
122- return recv
136+ if nob is None :
137+ nob = int (self .socket .recv (4 ), 16 )
138+ if DEBUG :
139+ print >> sys .stderr , " __receive: receiving" , nob , "bytes"
140+ recv = bytearray ()
141+ nr = 0
142+ while nr < nob :
143+ chunk = self .socket .recv (min ((nob - nr ), 4096 ))
144+ recv .extend (chunk )
145+ nr += len (chunk )
146+ if DEBUG :
147+ print >> sys .stderr , " __receive: returning len=" , len (recv )
148+ return str (recv )
123149
124150 def __checkOk (self ):
125151 if DEBUG :
@@ -221,7 +247,8 @@ def shell(self, cmd=None):
221247 return sout
222248
223249 def __getRestrictedScreen (self ):
224- ''' Gets mRestrictedScreen values from dumpsys. This is a method to obtain display dimensions '''
250+ ''' Gets C{mRestrictedScreen} values from dumpsys. This is a method to obtain display dimensions '''
251+
225252 rsRE = re .compile ('\s*mRestrictedScreen=\((?P<x>\d+),(?P<y>\d+)\) (?P<w>\d+)x(?P<h>\d+)' )
226253 for line in self .shell ('dumpsys window' ).splitlines ():
227254 m = rsRE .match (line )
@@ -278,6 +305,34 @@ def startActivity(self, component=None, flags=None, uri=None):
278305 cmd += ' %s' % uri
279306 self .shell (cmd )
280307
308+ def takeSnapshot (self , reconnect = False ):
309+ try :
310+ from PIL import Image
311+ except :
312+ raise Exception ("You have to install PIL to use takeSnapshot()" )
313+ self .__send ('framebuffer:' , checkok = True , reconnect = False )
314+ import struct
315+ #case 1: // version
316+ # return 12; // bpp, size, width, height, 4*(length, offset)
317+ received = self .__receive (1 * 4 + 12 * 4 )
318+ (version , bpp , size , width , height , roffset , rlen , boffset , blen , goffset , glen , aoffset , alen ) = struct .unpack ('<' + 'L' * 13 , received )
319+ mode = [None ]* 4
320+ mode [roffset / rlen ] = 'R'
321+ mode [boffset / blen ] = 'B'
322+ mode [goffset / glen ] = 'G'
323+ mode [aoffset / alen ] = 'A'
324+ mode = '' .join (mode )
325+ if DEBUG :
326+ print >> sys .stderr , " takeSnapshot:" , (version , bpp , size , width , height , roffset , rlen , boffset , blen , goffset , blen , aoffset , alen )
327+ self .__send ('\0 ' , checkok = False , reconnect = False )
328+ if DEBUG :
329+ print >> sys .stderr , " takeSnapshot: reading %d bytes" % (size )
330+ received = self .__receive (size )
331+ if reconnect :
332+ self .__connect ()
333+ self .__setTransport ()
334+ return Image .frombuffer (mode , (width , height ), received , 'raw' , mode , 0 , 1 )
335+
281336 def touch (self , x , y , eventType = DOWN_AND_UP ):
282337 self .shell ('input tap %d %d' % (x , y ))
283338
0 commit comments