Saturday, May 12, 2012

AndroidViewClient: Q&A

Q: Hi Diego, thanks for your sharing knowledge.
Now I have a question about how to implement a method like touchByText(self, text)instead of touching the Views by (x,y).


I just want to simply use text instead of android id.
Thank you.


(edited for clarity)

A: This is an interesting question that was posted as a comment to monkeyrunner: interacting with the Views and made me think about the possibility of including this functionality in AndroidViewClient.


After all, one of the most serious limitations of plain monkeyrunner is the need of the screen coordinates in MonkeyDevice.touch(integer x, integer y, integer type).
We have also analyzed here the use of the undocumented EasyMonkeyDevice in monkeyrunner: testing views properties where we described the current shortcomings.


So, fortunately, implementing this feature in AndroidViewClient was not so difficult and it's now available if you download the latest source code. To demonstrate it, we will be using a very simple Activity with 5 ToggleButtons named One, Two, Three, Four and Five.
Then, we will be using a monkeyrunner script using AndroidViewClient to find the buttons and touching them. After the script runs we will be able to see the five buttons in their On state.




The script that will toggle every button on is as follows:

#! /usr/bin/env monkeyrunner
'''
Copyright (C) 2012  Diego Torres Milano
Created on May 5, 2012
  
@author: diego
'''

import sys
import os
import time

# this must be imported before MonkeyRunner and MonkeyDevice,
# otherwise the import fails
try:
    ANDROID_VIEW_CLIENT_HOME = os.environ['ANDROID_VIEW_CLIENT_HOME']
except KeyError:
    print >>sys.stderr, "%s: ERROR: ANDROID_VIEW_CLIENT_HOME not set in environment" % __file__
    sys.exit(1)
sys.path.append(ANDROID_VIEW_CLIENT_HOME + '/src')
from com.dtmilano.android.viewclient import ViewClient

from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice

device = MonkeyRunner.waitForConnection(60, "emulator-5554")
if not device:
   raise Exception('Cannot connect to device')

MonkeyRunner.sleep(5)

vc = ViewClient(device)
vc.dump()

for bt in [ 'One', 'Two', 'Three', 'Four', 'Five' ]:
    b = vc.findViewWithAttribute('text:mText', bt)
    if b:
        (x, y) = b.getXY()
        print >>sys.stderr, "clicking b%s @ (%d,%d) ..." % (bt, x, y)
        b.touch()
    else:
        print >>sys.stderr, "b%s not found" % bt
    time.sleep(7)

print >>sys.stderr, "bye"


Once you run the script you will see how the state of the buttons is gradually changed.
I hope this example helps you getting started with AndroidViewClient.

37 comments:

rilwan said...
This comment has been removed by the author.
rilwan said...

i am getting keyerror for this line
>>> ANDROID_VIEW_CLIENT_HOME = os.environ['ANDROID_VIEW_CLIENT_HOME']
Traceback (most recent call last):
File "", line 1, in
KeyError: 'ANDROID_VIEW_CLIENT_HOME'
My PATH variable:-
root@svtuser:~# echo $PATH
/root/android-sdk-linux/tools/dtmilano-AndroidViewClient-f93204c/AndroidViewClient/src/com/dtmilano/android:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/root/android-sdk-linux/tools

Diego Torres Milano said...

ANDROID_VIEW_CLIENT_HOME is not set in your environment.
Try (all in the same line, the $ is the shell prompt):

$ export ANDROID_VIEW_CLIENT_HOME=/root/android-sdk-linux/tools/dtmilano-AndroidViewClient-f93204c/AndroidViewClient

AndroidViewClient does not look in the PATH to find its components.

rilwan said...

It worked.!!thanks a lot for the info.

rils said...
This comment has been removed by the author.
rilwan said...

Sometimes i am getting import Error:-
>>> ANDROID_VIEW_CLIENT_HOME = os.environ['ANDROID_VIEW_CLIENT_HOME']
>>> sys.path.append(ANDROID_VIEW_CLIENT_HOME + 'src')
>>> from com.dtmilano.android.viewclient import ViewClient
Traceback (most recent call last):
File "", line 1, in
ImportError: No module named dtmilano
>>> sys.path
['/home/svtuser/android-sdk-linux/tools/lib/monkeyrunner.jar', '/home/svtuser/android-sdk-linux/tools/lib/Lib', '/home/svtuser/android-sdk-linux/tools/lib/jython.jar/Lib', '__classpath__', '__pyclasspath__/', '/home/svtuser/android-sdk-linux/tools/AndroidViewClient/src']

Unknown said...

Hi Diego,

The book you wrote is quite wonderful.Can we have a talk about it?

My email address: rogerlzp@gmail.com
What's your email address?
Hope to hearing from you.

Thanks.
Roger

Hope so said...

Hi diego

Need one help
i created object of MonkeyView class from the function a=device.getViewById()
and when i am calling the function of Monkeyview class from the object a " a.getLocation()"

It giving me error
com.android.chimpchat.core.ChimpException: com.android.chimpchat.core.ChimpExcep
tion: No accessibility event has occured yet

Can u Help Me out for this problem

Hope so said...

Hi

reply if you use Monkeyview class

when i am calling any method of monkeyview class , getting the error
at com.android.chimpchat.ChimpManager.queryView(ChimpManager.java:414)
at com.android.chimpchat.core.ChimpView.queryView(ChimpView.java:52)
at com.android.chimpchat.core.ChimpView.getSelected(ChimpView.java:116)
at com.android.monkeyrunner.MonkeyView.getSelected(MonkeyView.java:97)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)


com.android.chimpchat.core.ChimpException: com.android.chimpchat.core.ChimpExcep
tion: No accessibility event has occured yet

Diego Torres Milano said...

@myfirstblog,
I'm not sure what you have done, but this is the pattern:

vc = ViewClient(device)
vc.dump()
view = vc.findViewById("id/whatever")

view is a ViewClient.View

Diego Torres Milano said...

@Hope so,
I don't understand where is the problem. Can you post some code and better description.

Hope so said...

a=device.getViewById("id/whatever")
a.getLocation()
According to http://source-android.frandroid.com/sdk/monkeyrunner/src/com/android/monkeyrunner/MonkeyDevice.java

a is object of MonkeyView class and
from a calling to getLocation function of class Monkeyview class
http://source-android.frandroid.com/sdk/monkeyrunner/src/com/android/monkeyrunner/MonkeyView.java

Unknown said...

Hi!
Can you please help me. i dont really understand how to install AndroidViewClient to use it:(
So when i try to import it a got
ERROR:
c:\monkeyrunner\Run2.py: ERROR: ANDROID_VIEW_CLIENT_HOME not set in environment

How can i solve it?
I use Windows 7 OS.

snoopy said...

Hi diego ,

you really do a great contribution to android testing.but now I meet a problem when I use your script.
I can not find the result if the text string have space .for example below . I will get nothing .but the hierarchyviewer can show the mTest.

Thanks In Advance!

text = 'Modules One'
view = vc.findViewWithText(text)
result: can not find ...

Ari said...

My issue would be about the same that previous poster said. If text:mText contains spaces, view isn't found.

Also in the situations view is found, clicking on a view can sometimes miss it. Coordinates don't seem to be accurate.

Very nice utility anyway, if these issues would be fixed benefits in using this would be enourmous.

Diego Torres Milano said...

@snoopy,
Thanks for your comments.
What you've found is a bug. It has been already identifyed (https://github.com/dtmilano/AndroidViewClient/blob/master/AndroidViewClient/src/com/dtmilano/android/viewclient.py#L264), however I didn't have time to think about a real solution yet.

I promise to take a look at soon as I have some free time.

Diego Torres Milano said...

@Spv Tv,
You have to set ANDROID_VIEW_CLIENT_HOME pointing to the AndroidViewClient directory in the script's (Run2.py in your case) environment.

Diego Torres Milano said...

@Ari,
I described the text with spaces problem in a previous comment.

The inaccurate position of views (x,y) is the other big problem.

I hope to have some time to look at them.

Patches are welcome. After all, that's why it is Open Source.

Diego Torres Milano said...

@Hope so,
What you have found ("No accessibility event has occured yet") is a monkey bug. I think it has been reported already.

Just in case, search for it in this bug search
and if it is not there you can report it using this bug report.


Hey, at least this one is not mine :-)

hi said...
This comment has been removed by the author.
hi said...

I have tried to use viewCliet in my application and I am able to run but I am getting the wrong X/Y axis and because of that even touch function is not working.

C:\Program Files\Android\android-sdk\tools>monkeyrunner.bat C:\Users\admin\Deskt
op\ViewClientExample\Example.py
Waiting for device connect....
Connected
Before Dump
After Dump
['_ViewClient__findViewWithAttributeInTree', '_ViewClient__splitAttrs', '__doc__
', '__init__', '__module__', 'assertServiceResponse', 'device', 'dump', 'findVie
wById', 'findViewByTag', 'findViewWithAttribute', 'findViewWithText', 'getRoot',
'getViewIds', 'parseTree', 'root', 'serviceResponse', 'setViews', 'traverse', '
views', 'viewsById']
clicking bWelcome @ (0,0) ...

I the above code you can see it is tring to clik on (0,0) but that is not the correct cordinate for the same.

Anonymous said...

please tell me the command to install androidviewclient in ubuntu using git...am new to git/android

Anonymous said...

please tell me the command to install it using git in ubuntu..i am new to git and android!

Diego Torres Milano said...

@Prachi Bhagat,
To obtain read-only access to the git repository:

$ cd somedir
$ git clone git://github.com/dtmilano/AndroidViewClient.git

Durairaj said...

Hi Diago, I have a situation. Whenever there is a edittext in the screen, the soft keyboard is popping up, and if I want to press a button though findViewById, (assuming that this particular button is behind the soft keyboard) fails. So as a work around I need to press back key through monkey runner. My question is how to determine whether soft keyboard is shown in the screen or not.

007 said...

Hi,
Is it possible to use AndroidViewClient directly from java code ? Examples are welcome if possible.

Diego Torres Milano said...

@007,
You can read http://dtmilano.blogspot.ca/2011/11/android-using-monkey-from-java.html if you are intending to use Java.

007 said...

We do use monkeyrunner (chimpchat) from Java but we couldn't figure out how to use WC module from Java?

Diego Torres Milano said...

@007,
WC?

007 said...

Typo. VC View Client module

Diego Torres Milano said...

@007,
Strictly speaking it's possible to do what AndroidViewClient does in python directly from Java rewriting AndroidViewClient in Java using chimpchat.

Why do you need it from Java?

007 said...

We have existing Java program where we would like to use AndroidViewClient module with monkeyrunner. We feel that using only Java would be nice since we can use chimpchat already. What do you think would be now the best pratice ?

Diego Torres Milano said...

@007,
Language selection is a personal preference. Python is very expressive and creating the tests could be simple but if you have a large investment in Java you would probably want to leverage it a create all your tests using that language.

Feel free to sponsor AndroidViewClient port to Java ;-)

Zellman said...

Hi Diego,
Thanks for the blog posts, they have been very helpful.

I imported AndroidViewClient, and I've hit an error that I'm not sure about. I never call __init__ in my script.

130116 16:52:13.124:S [MainThread] [com.android.monkeyrunner.MonkeyRunnerOptions] Script terminated due to an exception
130116 16:52:13.124:S [MainThread] [com.android.monkeyrunner.MonkeyRunnerOptions]Traceback (most recent call last):
File "/Users/zellman/monkeyrunner.py", line 47, in
viewclient = ViewClient(device)
TypeError: __init__() takes at least 3 arguments (2 given)

130116 16:52:13.124:S [MainThread] [com.android.monkeyrunner.MonkeyRunnerOptions] at org.python.core.PyException.fillInStackTrace(PyException.java:70)
...
130116 16:52:13.124:S [MainThread] [com.android.monkeyrunner.MonkeyRunnerOptions] at com.android.monkeyrunner.ScriptRunner.run(ScriptRunner.java:116)
130116 16:52:13.124:S [MainThread] [com.android.monkeyrunner.MonkeyRunnerOptions] at com.android.monkeyrunner.MonkeyRunnerStarter.run(MonkeyRunnerStarter.java:77)
130116 16:52:13.124:S [MainThread] [com.android.monkeyrunner.MonkeyRunnerOptions] at com.android.monkeyrunner.MonkeyRunnerStarter.main(MonkeyRunnerStarter.java:189)
130116 16:52:13.130:I [MainThread] [com.android.chimpchat.ChimpManager] Monkey Command: quit.

Diego Torres Milano said...

@Zellman,
ViewCient constructor (__init__()) takes at lease 2 arguments + self, so they are 3 in total.


class ViewClient:
'''
ViewClient is a I{ViewServer} client.

If not running the ViewServer is started on the target device or emulator and then the port
mapping is created.
'''

def __init__(self, device, serialno, adb=None, autodump=True, forceviewserveruse=False, localport=VIEW_SERVER_PORT, remoteport=VIEW_SERVER_PORT, startviewserver=True):


You have to specify device and serialno.

Tariq Ghalib said...

We have invested much time and effort on chimpchat & monkey runner using JAVA. Now this AndroidViewClient is no doubt an excellent tool which specially gives the ability to interact with UI very tightly (e.g click a button by its name(String)). But right now the drawback is we are missing AndroidViewClient JAVA support. We need the support for JAVA badly.

Diego Torres Milano said...

@Tariq,
Thanks for your comments.

Unfortunately, porting AndroidViewClient to Java is not in the roadmap yet. However being an Open Source project allows for somebody to do it. Of course, I will provide directions and help.

Alternatively. if the feature is vital for your project, sponsoring it would allow me or somebody else to afford some time to work on it as it has been done before.