Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

android get view hierarchy for all windows in activity

I am making SKD for Automation. So my needs are slightly different that normal app development.

Requirement: Get ViewHierarchy of current activity. Problem: I get it correct when Spinner is not open. I do not get the details of spinner when its open.

I use following code to get hierarchy. Questions is: Does Spinner get hosted in a different window which is why I am not getting it? What would be the way to get it?

    //This is how I start recursion to get view hierarchy
    View view = getWindow().getDecorView().getRootView();
    if (view instanceof ViewGroup) {
        ViewGroup group = (ViewGroup) view;
        dumpViewHierarchyWithProperties( group, 0);
    }

//Functions to get hierarchy
private  void dumpViewHierarchyWithProperties(ViewGroup group,int level) {
    if (!dumpViewWithProperties(group, level)) {
        return;
    }

    final int count = group.getChildCount();
    for (int i = 0; i < count; i++) {
        final View view = group.getChildAt(i);
        if (view instanceof ViewGroup) {
            dumpViewHierarchyWithProperties((ViewGroup) view, level + 1);
        } else {
            dumpViewWithProperties(view, level + 1);
        }
    }
}

private  boolean dumpViewWithProperties(View view,int level) {

    //Add to view Hierarchy.
    return true;
}
like image 548
TorukMakto Avatar asked Mar 06 '14 08:03

TorukMakto


1 Answers

I have managed to get the opened spinner popup view hierarchy using part of your code in addition to some other reflection magic, here is the full code, take in mind that reflection will affect the performance of your SDK and the applications that use it.

//Function to get all available windows of the application using reflection
private void logRootViews() {
    try {
        Class wmgClass = Class.forName("android.view.WindowManagerGlobal");
        Object wmgInstnace = wmgClass.getMethod("getInstance").invoke(null, (Object[])null);

        Method getViewRootNames = wmgClass.getMethod("getViewRootNames");
        Method getRootView = wmgClass.getMethod("getRootView", String.class);
        String[] rootViewNames = (String[])getViewRootNames.invoke(wmgInstnace, (Object[])null);

        for(String viewName : rootViewNames) {
            View rootView = (View)getRootView.invoke(wmgInstnace, viewName);
            Log.i(TAG, "Found root view: " + viewName + ": " + rootView);
            getViewHierarchy(rootView);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

//Functions to get hierarchy
private void getViewHierarchy(View view) {
    //This is how I start recursion to get view hierarchy
    if (view instanceof ViewGroup) {
        ViewGroup group = (ViewGroup) view;
        dumpViewHierarchyWithProperties(group, 0);
    } else {
        dumpViewWithProperties(view, 0);
    }
}

private void dumpViewHierarchyWithProperties(ViewGroup group, int level) {
    if (!dumpViewWithProperties(group, level)) {
        return;
    }

    final int count = group.getChildCount();
    for (int i = 0; i < count; i++) {
        final View view = group.getChildAt(i);
        if (view instanceof ViewGroup) {
            dumpViewHierarchyWithProperties((ViewGroup) view, level + 1);
        } else {
            dumpViewWithProperties(view, level + 1);
        }
    }
}

private boolean dumpViewWithProperties(View view, int level) {
    //Add to view Hierarchy.
    if (view instanceof TextView) {
        Log.d(TAG, "TextView from hierarchy dumped: " + view.toString() + " with text: " + ((TextView) view).getText().toString() + " ,in Level: " + level);
    } else {
        Log.d(TAG, "View from hierarchy dumped: " + view.toString() + " ,in Level: " + level);
    }
    return true;
}
like image 106
Emil Adz Avatar answered Nov 24 '22 23:11

Emil Adz