Подтвердить что ты не робот

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

Можно ли программно перечислить все android.view.Window s или декорации в приложении?

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

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

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

4b9b3361

Ответ 1

Я нашел способ сделать это через отражение на @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.example.paintsample/com.example.paintsample.PaintSample/[email protected]: com.android.internal.policy.impl.PhoneWindow $DecorView {41dcc278 V.E..... R....... 0,0-768,1184}

Найден корневой вид: PopupWindow: 42887380/[email protected]: android.widget.PopupWindow $PopupViewContainer {42891450 V.E............. 0,0-424,618}

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

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

И источник для android.jar для конкретной версии 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.example.paintsample/com.example.paintsample.PaintSample/[email protected]: com.android.internal.policy.impl.PhoneWindow $DecorView {41dcc278 VE.... R....... 0,0-768,1184}

Root view: PopupWindow: 42887380/[email protected]: android.widget.PopupWindow $PopupViewContainer {42891450 VE............ 0,0-424,618}