1818@author: Diego Torres Milano
1919
2020'''
21+ import random
2122import time
2223
23- __version__ = '10.5.3 '
24+ __version__ = '10.6.0 '
2425
2526import sys
2627import threading
4647 import ScrolledText
4748 import ttk
4849 from Tkconstants import DISABLED , NORMAL
50+
4951 TKINTER_AVAILABLE = True
5052except :
5153 TKINTER_AVAILABLE = False
6062DEBUG_ISCCOF = DEBUG and False
6163DEBUG_FIND_VIEW = DEBUG and False
6264DEBUG_CONTEXT_MENU = DEBUG and False
65+ DEBUG_CONCERTINA = DEBUG and False
6366
6467
6568class Color :
@@ -169,7 +172,7 @@ def checkDependencies():
169172This is usually installed by python package. Check your distribution details.
170173''' )
171174
172- def __init__ (self , vc , device , serialno , printOperation , scale = 1 ):
175+ def __init__ (self , vc , device , serialno , printOperation , scale = 1 , concertina = False ):
173176 '''
174177 Culebron constructor.
175178
@@ -183,13 +186,16 @@ def __init__(self, vc, device, serialno, printOperation, scale=1):
183186 @type printOperation: method
184187 @param scale: the scale of the device screen used to show it on the window
185188 @type scale: float
189+ @:param concertina: bool
190+ @:type concertina: enable concertina mode (see documentation)
186191 '''
187192
188193 self .vc = vc
189194 self .printOperation = printOperation
190195 self .device = device
191196 self .serialno = serialno
192197 self .scale = scale
198+ self .concertina = concertina
193199 self .window = Tkinter .Tk ()
194200 icon = resource_filename (Requirement .parse ("androidviewclient" ),
195201 "share/pixmaps/culebra.png" )
@@ -214,6 +220,7 @@ def __init__(self, vc, device, serialno, printOperation, scale=1):
214220 self .targetIds = []
215221 self .isTouchingPoint = self .vc is None
216222 self .coordinatesUnit = Unit .DIP
223+ self .permanentlyDisableEvents = False
217224 if DEBUG :
218225 try :
219226 self .printGridInfo ()
@@ -579,12 +586,11 @@ def getViewContainingPointAndTouch(self, x, y):
579586 text = tkSimpleDialog .askstring (title , "Enter text to type into this field" , ** kwargs )
580587 self .canvas .focus_set ()
581588 if text :
582- # This is deleting the existing text, which should be asked in the dialog, but I would have to implement
583- # the dialog myself
584- v .setText (text )
585- # This is not deleting the text, so appending if there's something
586- #v.type(text)
587- self .printOperation (v , Operation .TYPE , text )
589+ if self .vc .uiAutomatorHelper :
590+ oid = self .vc .uiAutomatorHelper .findObject (v .getId ())
591+ self .vc .uiAutomatorHelper .setText (oid , text )
592+ else :
593+ self .setText (v , text )
588594 else :
589595 self .hideVignette ()
590596 return
@@ -606,15 +612,28 @@ def findBestCandidate(view):
606612 if len (candidates ) > 2 :
607613 warnings .warn ("We are in trouble, we have more than one candidate to touch" , stacklevel = 0 )
608614 candidate = candidates [0 ]
609- candidate .touch ()
610- # we pass root=v as an argument so the corresponding findView*() searches in this
611- # subtree instead of the full tree
612- self .printOperation (candidate , Operation .TOUCH_VIEW , v if candidate != v else None )
615+ self .touchView (candidate , v if candidate != v else None )
613616
614617 self .printOperation (None , Operation .SLEEP , Operation .DEFAULT )
615618 self .vc .sleep (5 )
616619 self .takeScreenshotAndShowItOnWindow ()
617620
621+ def setText (self , v , text ):
622+ if DEBUG_CONCERTINA :
623+ print >> sys .stderr , "setText(%s, '%s')" % (v .__tinyStr__ (), text )
624+ # This is deleting the existing text, which should be asked in the dialog, but I would have to implement
625+ # the dialog myself
626+ v .setText (text )
627+ # This is not deleting the text, so appending if there's something
628+ # v.type(text)
629+ self .printOperation (v , Operation .TYPE , text )
630+
631+ def touchView (self , v , root = None ):
632+ v .touch ()
633+ # we pass root=v as an argument so the corresponding findView*() searches in this
634+ # subtree instead of the full tree
635+ self .printOperation (v , Operation .TOUCH_VIEW , root )
636+
618637 def touchPoint (self , x , y ):
619638 '''
620639 Touches a point in the device screen.
@@ -644,7 +663,7 @@ def touchPoint(self, x, y):
644663 time .sleep (5 )
645664 self .isTouchingPoint = self .vc is None
646665 self .takeScreenshotAndShowItOnWindow ()
647- self .hideVignette ()
666+ # self.hideVignette()
648667 self .statusBar .clear ()
649668 return
650669
@@ -676,7 +695,7 @@ def longTouchPoint(self, x, y):
676695 time .sleep (5 )
677696 self .isLongTouchingPoint = False
678697 self .takeScreenshotAndShowItOnWindow ()
679- self .hideVignette ()
698+ # self.hideVignette()
680699 self .statusBar .clear ()
681700 return
682701
@@ -756,7 +775,7 @@ def onKeyPressed(self, event):
756775 keysym = event .keysym
757776
758777 if len (char ) == 0 and not (
759- keysym in Culebron .KEYSYM_TO_KEYCODE_MAP or keysym in Culebron .KEYSYM_CULEBRON_COMMANDS ):
778+ keysym in Culebron .KEYSYM_TO_KEYCODE_MAP or keysym in Culebron .KEYSYM_CULEBRON_COMMANDS ):
760779 if DEBUG_KEY :
761780 print >> sys .stderr , "returning because len(char) == 0"
762781 return
@@ -961,6 +980,10 @@ def onCtrlQ(self, event):
961980 self .quit ()
962981
963982 def quit (self ):
983+ if self .vc .uiAutomatorHelper :
984+ if DEBUG or True :
985+ print >> sys .stderr , "Quitting UiAutomatorHelper..."
986+ self .vc .uiAutomatorHelper .quit ()
964987 self .window .destroy ()
965988
966989 def showSleepDialog (self ):
@@ -1047,6 +1070,8 @@ def drag(self, start, end, duration, steps, units=Unit.DIP):
10471070 self .takeScreenshotAndShowItOnWindow ()
10481071
10491072 def enableEvents (self ):
1073+ if self .permanentlyDisableEvents :
1074+ return
10501075 self .canvas .update_idletasks ()
10511076 self .canvas .bind ("<Button-1>" , self .onButton1Pressed )
10521077 self .canvas .bind ("<Control-Button-1>" , self .onCtrlButton1Pressed )
@@ -1057,7 +1082,8 @@ def enableEvents(self):
10571082 self .canvas .bind ("<Key>" , self .onKeyPressed )
10581083 self .areEventsDisabled = False
10591084
1060- def disableEvents (self ):
1085+ def disableEvents (self , permanently = False ):
1086+ self .permanentlyDisableEvents = permanently
10611087 if self .canvas is not None :
10621088 self .canvas .update_idletasks ()
10631089 self .areEventsDisabled = True
@@ -1185,8 +1211,71 @@ def mainloop(self):
11851211 self .window .title ("%s v%s" % (Culebron .APPLICATION_NAME , __version__ ))
11861212 self .window .resizable (width = Tkinter .FALSE , height = Tkinter .FALSE )
11871213 self .window .lift ()
1214+ if self .concertina :
1215+ self .concertinaLoop ()
1216+ else :
1217+ self .window .mainloop ()
1218+
1219+ def concertinaLoop (self ):
1220+ self .disableEvents (permanently = True )
1221+ self .concertinaLoopCallback (dontinteract = True )
11881222 self .window .mainloop ()
11891223
1224+ def concertinaLoopCallback (self , dontinteract = False ):
1225+ if not dontinteract :
1226+ if DEBUG_CONCERTINA :
1227+ print >> sys .stderr , "CONCERTINA: should select one if these targets:"
1228+ for v in self .targetViews :
1229+ print >> sys .stderr , " " , unicode (v .__tinyStr__ ())
1230+ l = len (self .targetViews )
1231+ if l > 0 :
1232+ i = random .randrange (len (self .targetViews ))
1233+ t = self .targetViews [i ]
1234+ z = self .targets [i ]
1235+ if DEBUG_CONCERTINA :
1236+ print >> sys .stderr , "CONCERTINA: selected" , unicode (t .__smallStr__ ())
1237+ print >> sys .stderr , "CONCERTINA: selected" , z
1238+ self .markTarget (* z )
1239+ self .window .update_idletasks ()
1240+ time .sleep (1 )
1241+ # FIXME: we need self.unmakeTarget(*z)
1242+ self .unmarkTargets ()
1243+ clazz = t .getClass ()
1244+ parent = t .getParent ()
1245+ if parent :
1246+ parentClass = parent .getClass ()
1247+ else :
1248+ parentClass = None
1249+ isScrollable = t .isScrollable ()
1250+ if DEBUG_CONCERTINA :
1251+ print >> sys .stderr , "CONCERTINA: is scrollable: " , isScrollable
1252+ if clazz == 'android.widget.EditText' :
1253+ text = 'Some random text'
1254+ if DEBUG_CONCERTINA :
1255+ print >> sys .stderr , "Entering text: " , text
1256+ self .setText (t , text )
1257+ elif isScrollable or parentClass == 'android.widget.ScrollView' :
1258+ # NOTE: The order here is important because some EditText are inside ScrollView's and we want to
1259+ # capture the case of other ScrollViews
1260+ print >> sys .stderr , ">>>>>>>>" , t .getBounds ()
1261+ ((t , l ), (b , r )) = t .getBounds ()
1262+ sp = (t + 50 , (r - l )/ 2 )
1263+ ep = (b - 50 , (r - l )/ 2 )
1264+ d = 1
1265+ s = 20
1266+ units = Unit .DIP
1267+ if DEBUG_CONCERTINA :
1268+ print >> sys .stderr , "CONCERTINA: dragging %s %s %s %s %s" % (sp , ep , d , s , units )
1269+ self .drag (sp , ep , d , s , units )
1270+ else :
1271+ self .touchView (t )
1272+ self .printOperation (None , Operation .SLEEP , Operation .DEFAULT )
1273+ time .sleep (5 )
1274+ self .takeScreenshotAndShowItOnWindow ()
1275+ else :
1276+ print >> sys .stderr , "CONCERTINA: No target views"
1277+ self .window .after (5000 , self .concertinaLoopCallback )
1278+
11901279
11911280if TKINTER_AVAILABLE :
11921281 class MainMenu (Tkinter .Menu ):
@@ -1612,7 +1701,7 @@ def __init__(self, culebron, view):
16121701 culebron .showSleepDialog ))
16131702 if culebron .vc is not None :
16141703 items .append (ContextMenu .Command ('Toggle generating Test Condition' , 18 , 'Ctrl+T' , '<Control-T>' ,
1615- culebron .toggleGenerateTestCondition ))
1704+ culebron .toggleGenerateTestCondition ))
16161705 items .append (ContextMenu .Command ('Touch Zones' , 6 , 'Ctrl+Z' , '<Control-Z>' , culebron .toggleTargetZones ))
16171706 items .append (ContextMenu .Command ('Generates a startActivity()' , 17 , 'Ctrl+A' , '<Control-A>' ,
16181707 culebron .printStartActivityAtTop ))
0 commit comments