Culebra helps you create AndroidViewClient scripts generating a working template that can be modified to suit more specific needs.
__ __ __ __ / \ / \ / \ / \ ____________________/ __\/ __\/ __\/ __\_____________________________ ___________________/ /__/ /__/ /__/ /________________________________ | / \ / \ / \ / \ \___ |/ \_/ \_/ \_/ \ o \ \_____/--<
@author: diego @author: Jennifer E. Swofford (ascii art snake)
culebra is another extremely valuable tool in AndroidViewClient toolbox.
Its main use is to generate templates or scripts that can later be adapted to suit the most demanding needs. It conveys the full power of AndroidViewClient and python together.
dump.py is a script that helps obtaining the dump of the content of the screen currently present on a device or emulator.
dump.py provides the result as a tree of Views representing the logical content of the screen.
In a similar fashion,
culebra generates a script, the logically represents and verifies the content of the screen, but instead of comparing bitmaps or using optical character recognition it uses Views properties as main component. In this script
culebra can find and verify the existence of Views having a specific ID, some text or text matching some pattern or content descriptions.
Some time ago, I wrote an article about visual image comparison in monkeyrunner, which is also a valid approach for some situations, but the ability to obtain the tree of Views provides a flexibility and effectiveness very difficult to parallel using graphical methods. One of the advantages is the device, screen, resolution and density independence that allows to run the same test on different devices.
In order to run
dump.py and any other AndroidViewClient script some environment variables should be provided containing the right values that allow the script to find other components.
PATH should contain the
In the example above
<android-sdk> represents the path to your Android SDK installation directory.
ANDROID_VIEW_CLIENT_HOME contains the path to the AndroidViewClient directory. This is the directory containing
ANDROID_VIEW_CLIENT_VERSION contains the version number of the jar file that will be loaded as plugin from
This is a string like
PYTHONPATH alternatively this variable can be used to locate modules. This is very useful when scripts are run from Eclipse using PyDev.
usage: culebra [OPTION]... [serialno] Options: -H, --help prints this help -V, --verbose -I, --ignore-secure-device -F, --force-view-server-use -S, --do-not-start-view-server -o, --output=FILE output to FILE -i, --find-views-by-id=BOOL whether to use findViewById() in script -t, --find-views-with-text=BOOL whether to use findViewWithText() in script -d, --find-views-with-content-description=BOOL whether to sue findViewWithContentDescription -r, --use-regexps use regexps in matches -C, --verbose-comments -U, --unit-test generates unit test script -j, --use-jar=BOOL use jar and appropriate shebang to run script -D, --use-dictionary=BOOL use a dictionary to store the Views found -R, --auto-regexps=LIST auto regexps (i.e. clock)
Prints the help message and command line usage
Sets the verbose mode for the script.
Ignores that a device is in secured as explained in secure mode.
This is useful when used in combination with LocalViewServer.
Forces the use of ViewServer even if the conditions to use UiAutomator are present. These conditions are depicted in Select the correct implementation. Basically, if the device run on API 16 or greater it can use UiAutomator, but if for some reason you want to still use the previous ViewServer method you can force it using this option.
ViewServer is much slower than UiAutomator, so it seems there are no reasons to use it when the latter is available. However there is one reason that may have some weight and this is the availability of the same View ID's used in the layouts.
Avoids starting the ViewServer even when it's not present on the device.
This is useful when used in combination with LocalViewServer.
Saves the output of this tool to
FILE execute permission is also set when this option is used to be able to run it.
Whether to use
findViewById() in the generated script.
Whether to use
findViewByWithText() in the generated script.
Whether to sue
findViewWithContentDescription() in the generated script.
Use regexps in matches. Every time a selection is done it will use a regexp match instead of text.
Generates verbose comments in the script.
Generates unit test script.
Whether to use the
jar and appropriate
shebang to run script.
Use a dictionary to store the Views found.
When used in conjunction with
--use-regexps some cases are identified and
the pattern is automatically replaced by pre-existing patterns.
LIST is the list of replacements to apply separated by
The supported pre-existing matches are:
Specifies the serial number of the device to use if the device serial number cannot be determined automatically for some reason or if there are several devices connected.
This examples uses UiAutomator as the API 16 present in the emulator allows it.
The following command line creates the script not using IDs, using content description regexps to find the views and using the AndroidViewClient jar file
$ culebra -i false -d true -r -j true
the script obtained is
#! /usr/bin/env shebang monkeyrunner -plugin $ANDROID_VIEW_CLIENT_HOME/bin/androidviewclient-2.3.11.jar @! # -*- coding: utf-8 -*- ''' Copyright (C) 2013 Diego Torres Milano Created on 2013-04-16 by Culebra v0.9.5 __ __ __ __ / \ / \ / \ / \ ____________________/ __\/ __\/ __\/ __\_____________________________ ___________________/ /__/ /__/ /__/ /________________________________ | / \ / \ / \ / \ \___ |/ \_/ \_/ \_/ \ o \ \_____/--< @author: diego @author: Jennifer E. Swofford (ascii art snake) ''' import re import sys import os from com.dtmilano.android.viewclient import ViewClient from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice device, serialno = ViewClient.connectToDeviceOrExit() vc = ViewClient(device, serialno) no_id9 = vc.findViewWithContentDescriptionOrRaise(re.compile('Apps')) no_id10 = vc.findViewWithContentDescriptionOrRaise(re.compile('Widgets')) no_id15 = vc.findViewWithContentDescriptionOrRaise(re.compile('Analog clock')) no_id20 = vc.findViewWithContentDescriptionOrRaise(re.compile('API Demos')) no_id25 = vc.findViewWithContentDescriptionOrRaise(re.compile('ApiDemos')) no_id30 = vc.findViewWithContentDescriptionOrRaise(re.compile('Bookmark')) no_id35 = vc.findViewWithContentDescriptionOrRaise(re.compile('Bookmarks')) no_id40 = vc.findViewWithContentDescriptionOrRaise(re.compile('Calendar'))
The generated script uses
shebang as shebang to be able to easily locate AndroidViewClient and simplify imports.
Then the usual device connection and ViewClient instantiation. Once the ViewClient reference is obtained a series of method calls are generated locating the Views currently on the device screen.
In this particular case, because we specified it in culebra command line we are generating only content description calls and using regular expressions as arguments.
You can take a look at the screenshot presented before and check that the main Views, having a valid content description, are the ones in the script.
Because no serialno was specified on the command line the regular expression
.* that matches any device or emulator is used. In this case the only device present is the emulator-5554.
It's not possible to determine the serial number for the emulator and thus the warning tells us that emulator-5554 was assumed.
If we save the generated script we can execute it at a later time.
$ culebra -i false -d true -r -j true -o example1.py
Now, when we execute the script, and the device contains the same screen, that is the same Views (strictly speaking Views with the same content description as before as we are not imposing any other rules in this simple example) the script will exit with no errors
However, if we change the screen, let's say manually selecting the Apps tab and run the script again
$ ./example1.py ... com.dtmilano.android.viewclient.ViewNotFoundException: Couldn't find View with content-desc that matches 'Analog clock' in tree with root=ROOT ...
We receive the exception telling us that a View with a content description matching 'Alarm clock' was not found.
Last edited by Diego Torres Milano,