Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to programmatically locate all Windows within a given application?

Is it possible to programmatically enumerate all of the android.view.Windows, or decor views within an application?

Dialogs for example will both open in a new Window, separate from the main Activity window. I can locate them via Dialog.getWindow() but I'm not sure how I would do this with a built-in components such as the activity menu popup.

Is there any way, from an Application, Context, or the WindowManager, or something else, to enumerate the Windows associated with my app?

I can see all of my application's windows with adb dumpsys window, but I'm looking for a way to do this within my application without requiring root.

like image 589
Andrew Lavers Avatar asked Oct 29 '13 21:10

Andrew Lavers


3 Answers

I've found a way to do it via reflection on the @hidden WindowManagerGlobal. At least so far I know this works for android-18.

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);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Output:

Found root view: com.example.paintsample/com.example.paintsample.PaintSample/android.view.ViewRootImpl@41deeff0: com.android.internal.policy.impl.PhoneWindow$DecorView{41dcc278 V.E..... R....... 0,0-768,1184}

Found root view: PopupWindow:42887380/android.view.ViewRootImpl@42891820: android.widget.PopupWindow$PopupViewContainer{42891450 V.E..... ........ 0,0-424,618}

Bounty is still up for grabs of course for anyone who can find a better way :)

like image 113
Andrew Lavers Avatar answered Nov 11 '22 02:11

Andrew Lavers


I'm not entirely sure this answers the actual question, but it's a better way of getting all root views as suggested in the accepted answer.

As mentioned there, I've also managed to accomplish this only using reflection, except this code supports All versions from API 14 and above (I haven't checked below):

public static List<View> getWindowManagerViews() {
    try {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH &&
                Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {

            // get the list from WindowManagerImpl.mViews
            Class wmiClass = Class.forName("android.view.WindowManagerImpl");
            Object wmiInstance = wmiClass.getMethod("getDefault").invoke(null);

            return viewsFromWM(wmiClass, wmiInstance);

        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {

            // get the list from WindowManagerGlobal.mViews
            Class wmgClass = Class.forName("android.view.WindowManagerGlobal");
            Object wmgInstance = wmgClass.getMethod("getInstance").invoke(null);

            return viewsFromWM(wmgClass, wmgInstance);
        }

    } catch (Exception e) {
        e.printStackTrace();
    }

    return new ArrayList<View>();
}

private static List<View> viewsFromWM(Class wmClass, Object wmInstance) throws Exception {

    Field viewsField = wmClass.getDeclaredField("mViews");
    viewsField.setAccessible(true);
    Object views = viewsField.get(wmInstance);

    if (views instanceof List) {
        return (List<View>) viewsField.get(wmInstance);
    } else if (views instanceof View[]) {
        return Arrays.asList((View[])viewsField.get(wmInstance));
    }

    return new ArrayList<View>();
}
like image 37
Boris Avatar answered Nov 11 '22 01:11

Boris


The Hierarchyviewer tool that comes with the SDK is worth its weight in gold.

like image 4
Pedantic Avatar answered Nov 11 '22 02:11

Pedantic