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:

  1. This comment has been removed by the author.

    ReplyDelete
  2. 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

    ReplyDelete
  3. 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.

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

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
  6. 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']

    ReplyDelete
  7. 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

    ReplyDelete
  8. 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

    ReplyDelete
  9. 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

    ReplyDelete
  10. @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

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

    ReplyDelete
  12. 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

    ReplyDelete
  13. 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.

    ReplyDelete
  14. 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 ...

    ReplyDelete
  15. 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.

    ReplyDelete
  16. @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.

    ReplyDelete
  17. @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.

    ReplyDelete
  18. @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.

    ReplyDelete
  19. @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 :-)

    ReplyDelete
  20. This comment has been removed by the author.

    ReplyDelete
  21. 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.

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

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

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

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

    ReplyDelete
  25. 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.

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

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

    ReplyDelete
  28. Typo. VC View Client module

    ReplyDelete
  29. @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?

    ReplyDelete
  30. 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 ?

    ReplyDelete
  31. @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 ;-)

    ReplyDelete
  32. 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.

    ReplyDelete
  33. @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.

    ReplyDelete
  34. 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.

    ReplyDelete
  35. @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.

    ReplyDelete