有没有办法以编程方式在给定的应用程序中找到所有Windows?

And*_*ers 18 android android-view android-window

是否可以以编程方式枚举android.view.Window应用程序中的所有s或装饰视图?

Dialogs例如,它们都将在一个新的中打开Window,与主Activity窗口分开.我可以通过Dialog.getWindow()它找到它们,但我不确定如何使用内置组件(如活动菜单弹出窗口)执行此操作.

有什么办法,从Application,Context或者WindowManager,还是其他什么东西,枚举与我的应用程序关联的Windows?

我可以看到我的所有应用程序的窗口adb dumpsys window,但我正在寻找一种方法在我的应用程序中执行此操作而不需要root.

And*_*ers 19

我已经找到了一种方法来通过反射来做到这一点@hidden WindowManagerGlobal.至少到目前为止我知道这适用于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();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

找到根视图:com.example.paintsample/com.example.paintsample.PaintSample/android.view.ViewRootImpl@41deeff0:com.android.internal.policy.impl.PhoneWindow $ DecorView {41dcc278 VE .... R ... ...... 0,0-768,1184}

找到根视图:PopupWindow:42887380/android.view.ViewRootImpl@42891820:android.widget.PopupWindow $ PopupViewContainer {42891450 VE .... ........ 0,0-424,618}

对于能找到更好方法的人来说,赏金当然还在争夺中:)


Bor*_*ris 12

我不完全确定这会回答实际问题,但这是获得所有根视图的更好方法,如接受的答案所示.

正如那里提到的,我还设法只使用反射完成此操作,除了此代码支持API 14及更高版本的所有版本(我没有在下面检查):

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>();
}
Run Code Online (Sandbox Code Playgroud)