Search code examples
androidmonkeyrunnergui-testing

Android: get UI element tree from code (ChimpChat or monkeyrunner) over Hierarchy viewer


I want to get all active UI elements from an (active) Activity without accessing the code. Exactly like the Hierarchy Viewer Tool, just from code. At the moment I use the .jar files behind the monkeyrunner tool in java, but using the python API wouldn't be a problem, I could switch if necessary. :-) So I connect to the emulator and start the init HierarchyViewer like this:

m_chimpchat = ChimpChat.getInstance(options);
m_device = m_chimpchat.waitForConnection(5000, ".*");
HierarchyViewer hv = m_device.getHierarchyViewer();

(Python equivalent would be)

device = MonkeyRunner.waitForConnection()
hv = device.getHierarchyViewer()

But that's it. I don't know how to get the UI elements from here. It must be possible because the Hierarchy Viewer Tool can do that.

If possible, I want to know what kind of UI component it is, an id, its position (x, y) and its txts (for example Button txt, TextView, ...) to implement tests.

Thanks, Soeren


Solution

  • AndroidViewClient is an extension to monkeyrunner that simplifies some things and also correct some other things that monkeyrunner alone would give you incorrectly, like the position of some Views depending on several conditions (i.e. status bar present).

    This is one of the examples present in AndroidViewClient source distribution and does precisely what you ask:

    #! /usr/bin/env monkeyrunner
    '''
    Copyright (C) 2012  Diego Torres Milano
    Created on Feb 3, 2012
    
    @author: diego
    '''
    
    
    import re
    import sys
    import os
    
    # This must be imported before MonkeyRunner and MonkeyDevice,
    # otherwise the import fails.
    # PyDev sets PYTHONPATH, use it
    try:
        for p in os.environ['PYTHONPATH'].split(':'):
            if not p in sys.path:
                sys.path.append(p)
    except:
        pass
    
    try:
        sys.path.append(os.path.join(os.environ['ANDROID_VIEW_CLIENT_HOME'], 'src'))
    except:
        pass
    
    from com.dtmilano.android.viewclient import ViewClient
    
    device, serialno = ViewClient.connectToDeviceOrExit()
    ViewClient(device=device, serialno=serialno).traverse(transform=ViewClient.TRAVERSE_CIT)
    

    The ViewClient.traverse() method traverses the tree and invokes the method specified as the transform argument for every View. In this case, one of the provided method is used which prints the View class, id and text (CIT) if any.

    Some other information can be found at http://dtmilano.blogspot.com/2012/02/monkeyrunner-interacting-with-views.html.