Есть ли способ программно найти все окна в данном приложении?

можно ли программно перечислить все android.view.WindowS или виды декора в приложении?

Dialogs например, оба откроются в новом Window, отдельно от главного окна действия. Я могу найти их через Dialog.getWindow() но я не уверен, как я бы это сделал со встроенными компонентами, такими как всплывающее меню активности.

есть ли какой-либо способ, от Application, Context или WindowManager или что-то еще, чтобы перечислить окна, связанные с мое приложение?

Я вижу все окна моего приложения с adb dumpsys window, но я ищу способ сделать это в моем приложении, не требуя корень.

4 ответов


Я нашел способ сделать это через отражение на @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();
    }
}

выход:

найден корневой вид: com.образец.paintsample / com.образец.paintsample.PaintSample / android.вид.ViewRootImpl@41deeff0: com.андроид.внутренний.политика.impl.PhoneWindow$DecorView{41dcc278 В. Е..... Р....... 0,0-768,1184}

найден корневой вид: PopupWindow: 42887380 / android.вид.ViewRootImpl@42891820: андроид.штучка.PopupWindow$PopupViewContainer{42891450 В. Е..... ........ 0,0-424,618}

Баунти все еще для захватов, конечно, для тех, кто может найти лучший способ :)


Я не совсем уверен, что это отвечает на фактический вопрос, но это лучший способ получить все корневые представления, как предложено в принятом ответе.

Как уже упоминалось, мне также удалось выполнить это только с помощью отражения, за исключением того, что этот код поддерживает все версии из 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>();
}

на Hierarchyviewer инструмент, который поставляется с SDK, стоит своего веса в золоте.


вы можете использовать @hidden APIs напрямую, без использования отражения, получая доступ к файлам классов и добавляя их в свой android.jar в Android SDK. Вот как: https://devmaze.wordpress.com/2011/01/18/using-com-android-internal-part-1-introduction/

и источник для android.банку для конкретной версии android (19,21,22,23,24) можно схватить здесь: https://github.com/anggrayudi/android-hidden-api

таким образом, вы можете использовать Класс WindowManagerGlobal напрямую, чтобы получить всю корневую вид вроде

private void logRootViews() {
    WindowManagerGlobal windowManagerGlobal = WindowManagerGlobal.getInstance();
    String[] rootViewNames = windowManagerGlobal.getViewRootNames();

    for (String viewName : rootViewNames) {
        View rootView = windowManagerGlobal.getRootView(viewName);
        Log.i("", "Root view is: " + viewName + ": " + rootView);
        /*do what you want with the rootView*/
    }
}

выход:

корневой вид: com.образец.paintsample / com.образец.paintsample.PaintSample / android.вид.ViewRootImpl@41deeff0: com.андроид.внутренний.политика.impl.PhoneWindow$DecorView{41dcc278 В. Е..... Р....... 0,0-768,1184}

корневой вид: PopupWindow:42887380 / android.вид.ViewRootImpl@42891820: android.штучка.PopupWindow$PopupViewContainer{42891450 В. Е..... ........ 0,0-424,618}