首页 > 其他分享 >3【Android 12】DisplayArea层级结构

3【Android 12】DisplayArea层级结构

时间:2022-09-05 22:58:51浏览次数:98  
标签:DisplayArea 12 Leaf areaForLayer Android WindowedMagnification Root HideDisplayC

1 DisplayArea类的继承关系

DisplayArea类的继承关系,之前已经分析过,这里用一张简单的类图总结:

image

2 DisplayArea层级结构的生成

既然DisplayContent是作为其代表的屏幕的DisplayArea层级结构的根节点,那么从DisplayContent出发,看一下这棵以DisplayContent为根节点的DisplayArea树是如何生成的。

2.1 DisplayContent.init

    /**
     * Create new {@link DisplayContent} instance, add itself to the root window container and
     * initialize direct children.
     * @param display May not be null.
     * @param root {@link RootWindowContainer}
     */
    DisplayContent(Display display, RootWindowContainer root) {
        // ......

        // Setup the policy and build the display area hierarchy.
        mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(
                mWmService, this /* content */, this /* root */, mImeWindowsContainer);

        // ......
    }

在DisplayContent的构造方法中,调用DisplayAreaPolicy.Provider.instantiate方法,去初始化一个DisplayArea层级结构。

2.2 DisplayAreaPolicy.DefaultProvider.instantiate

DisplayAreaPolicy.Provider只是一个接口,instantiate定义为:

        /**
         * Instantiates a new {@link DisplayAreaPolicy}. It should set up the {@link DisplayArea}
         * hierarchy.
         *
         * @see DisplayAreaPolicy#DisplayAreaPolicy
         */
        DisplayAreaPolicy instantiate(WindowManagerService wmService, DisplayContent content,
                RootDisplayArea root, DisplayArea.Tokens imeContainer);

用来实例化一个DisplayAreaPolicy对象,这个对象应该建立起DisplayArea层级结构,实际走到的则是DisplayAreaPolicy.Provider的实现类DisplayAreaPolicy.DefaultProvider.instantiate方法:

        @Override
        public DisplayAreaPolicy instantiate(WindowManagerService wmService,
                DisplayContent content, RootDisplayArea root,
                DisplayArea.Tokens imeContainer) {
            final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService,
                    "DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);
            final List<TaskDisplayArea> tdaList = new ArrayList<>();
            tdaList.add(defaultTaskDisplayArea);

            // Define the features that will be supported under the root of the whole logical
            // display. The policy will build the DisplayArea hierarchy based on this.
            final HierarchyBuilder rootHierarchy = new HierarchyBuilder(root);
            // Set the essential containers (even if the display doesn't support IME).
            rootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList);
            if (content.isTrusted()) {
                // Only trusted display can have system decorations.
                configureTrustedHierarchyBuilder(rootHierarchy, wmService, content);
            }

            // Instantiate the policy with the hierarchy defined above. This will create and attach
            // all the necessary DisplayAreas to the root.
            return new DisplayAreaPolicyBuilder().setRootHierarchy(rootHierarchy).build(wmService);
        }

2.2.1 创建HierarchyBuilder

首先注意到,这里的RootDisplayArea类型的传参root即是一个DisplayContent对象,毕竟它是要作为后续创建的DisplayArea层阶结构的根节点。然后根据这个传入的DisplayContent,创建一个HierarchyBuilder对象:

            // Define the features that will be supported under the root of the whole logical
            // display. The policy will build the DisplayArea hierarchy based on this.
            final HierarchyBuilder rootHierarchy = new HierarchyBuilder(root);

HierarchyBuilder定义在DisplayAreaPolicyBuilder中:

    /**
     *  Builder to define {@link Feature} and {@link DisplayArea} hierarchy under a
     * {@link RootDisplayArea}
     */
    static class HierarchyBuilder {

HierarchyBuilder用来构建一个DisplayArea层级结构,该层级结构的根节点,则是HierarchyBuilder构造方法中传入的RootDisplayArea:

	private final RootDisplayArea mRoot;

	// ......

	HierarchyBuilder(RootDisplayArea root) {
            mRoot = root;
        }

这里传入的则是一个DisplayContent对象,那么HierarchyBuilder要以这个DisplayContent对象为根节点,生成一个DisplayArea层级结构。

2.2.2 保存ImeContainer到HierarchyBuilder内部

传参imeContainer,则是DisplayContent的成员变量:

// Contains all IME window containers. Note that the z-ordering of the IME windows will depend
// on the IME target. We mainly have this container grouping so we can keep track of all the IME
// window containers together and move them in-sync if/when needed. We use a subclass of
// WindowContainer which is omitted from screen magnification, as the IME is never magnified.
// TODO(display-area): is "no magnification" in the comment still true?
private final ImeContainer mImeWindowsContainer = new ImeContainer(mWmService);

即ImeContainer类型的DisplayArea,在定义的时候已经初始化。

通过HierarchyBuilder.setImeContainer方法:

        @Nullable
        private DisplayArea.Tokens mImeContainer;

		// ......

		/** Sets IME container as a child of this hierarchy root. */
        HierarchyBuilder setImeContainer(DisplayArea.Tokens imeContainer) {
            mImeContainer = imeContainer;
            return this;
        }

将DisplayContent的mImeWindowsContainer保存在了HierarchyBuilder的mImeContainer成员变量中,后续创建DisplayArea层级结构时可以直接拿来使用。

2.2.3 创建并保存默认TaskDisplayArea到HierarchyBuilder内部

创建一个名为“DefaultTaskDisplayArea”的TaskDisplayArea:

            final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService,
                    "DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);

然后将该TaskDisplayArea添加到一个局部List中,调用HierarchyBuilder.setTaskDisplayAreas方法,将该对象保存在了HierarchyBuilder.mTaskDisplayAreas中。

        private final ArrayList<TaskDisplayArea> mTaskDisplayAreas = new ArrayList<>();
        
		// ......

        /**
         * Sets {@link TaskDisplayArea} that are children of this hierarchy root.
         * {@link DisplayArea} group must have at least one {@link TaskDisplayArea}.
         */
        HierarchyBuilder setTaskDisplayAreas(List<TaskDisplayArea> taskDisplayAreas) {
            mTaskDisplayAreas.clear();
            mTaskDisplayAreas.addAll(taskDisplayAreas);
            return this;
        }

另外看到,虽然TaskDisplayArea是支持嵌套的,并且这里也采用了一个ArrayList来管理TaskDisplayArea,但是目前TaskDisplayArea只在这里被创建,即目前一个DisplayContent只有一个名为“DefaultTaskDisplayArea”的TaskDisplayArea。

因为TaskDisplayArea是用来管理Task的,而Task本身就支持嵌套,再加上TaskOrgnizerController,光这两者已经可以为TaskDisplayArea建立起一个比较复杂的Task层级结构了,因此TaskDisplayArea的嵌套目前显得没有必要。

2.2.4 为HierarchyBuilder添加Feature

调用DisplayAreaPolicy.DefaultProvider.configureTrustedHierarchyBuilder为HierarchyBuilder添加Feature:

            if (content.isTrusted()) {
                // Only trusted display can have system decorations.
                configureTrustedHierarchyBuilder(rootHierarchy, wmService, content);
            }

接着来看DisplayAreaPolicy.DefaultProvider.configureTrustedHierarchyBuilder方法的具体内容:

        private void configureTrustedHierarchyBuilder(HierarchyBuilder rootHierarchy,
                WindowManagerService wmService, DisplayContent content) {
            // WindowedMagnification should be on the top so that there is only one surface
            // to be magnified.
            rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",
                    FEATURE_WINDOWED_MAGNIFICATION)
                    .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                    .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                    // Make the DA dimmable so that the magnify window also mirrors the dim layer.
                    .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
                    .build());
            if (content.isDefaultDisplay) {
                // Only default display can have cutout.
                // See LocalDisplayAdapter.LocalDisplayDevice#getDisplayDeviceInfoLocked.
                rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "HideDisplayCutout",
                        FEATURE_HIDE_DISPLAY_CUTOUT)
                        .all()
                        .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL, TYPE_STATUS_BAR,
                                TYPE_NOTIFICATION_SHADE)
                        .build())
                        .addFeature(new Feature.Builder(wmService.mPolicy,
                                "OneHandedBackgroundPanel",
                                FEATURE_ONE_HANDED_BACKGROUND_PANEL)
                                .upTo(TYPE_WALLPAPER)
                                .build())
                        .addFeature(new Feature.Builder(wmService.mPolicy, "OneHanded",
                                FEATURE_ONE_HANDED)
                                .all()
                                .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)
                                .build());
            }
            rootHierarchy
                    .addFeature(new Feature.Builder(wmService.mPolicy, "FullscreenMagnification",
                            FEATURE_FULLSCREEN_MAGNIFICATION)
                            .all()
                            .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, TYPE_INPUT_METHOD,
                                    TYPE_INPUT_METHOD_DIALOG, TYPE_MAGNIFICATION_OVERLAY,
                                    TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)
                            .build())
                    .addFeature(new Feature.Builder(wmService.mPolicy, "ImePlaceholder",
                            FEATURE_IME_PLACEHOLDER)
                            .and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
                            .build());
        }

如果当前DisplayContent是默认屏幕,那么会为HierarchyBuilder添加6种Feature,否则是3种,我们只分析一般情况,即当前屏幕是默认屏幕的情况。

Feature是DisplayAreaPolicyBuilder的内部类:

    /**
     * A feature that requires {@link DisplayArea DisplayArea(s)}.
     */
    static class Feature {
        private final String mName;
        private final int mId;
        private final boolean[] mWindowLayers;
        private final NewDisplayAreaSupplier mNewDisplayAreaSupplier;

首先Feature代表的是DisplayArea的一个特征,可以根据Feature来对不同的DisplayArea进行划分。

看一下它的成员变量:

  • mName,很好理解,这个Feature的名字,如上面的“WindowedMagnification”,“HideDisplayCutout”之类的,后续DisplayArea层级结构建立起来后,每个DisplayArea的名字用的就是当前DisplayArea对应的那个Feature的名字。
  • mId,Feature的ID,如上面的FEATURE_WINDOWED_MAGNIFICATION和FEATURE_HIDE_DISPLAY_CUTOUT,虽说是Feature的ID,因为Feature又是DisplayArea的特征,所以这个ID也可以直接代表DisplayArea的一种特征。
  • mWindowLayers,代表了这个DisplayArea可以包含哪些层级对应的窗口,后续会分析到。
  • mNewDisplayAreaSupplier,

先看第一个Feature:

            // WindowedMagnification should be on the top so that there is only one surface
            // to be magnified.
            rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",
                    FEATURE_WINDOWED_MAGNIFICATION)
                    .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                    .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                    // Make the DA dimmable so that the magnify window also mirrors the dim layer.
                    .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
                    .build());

1)、设置Feature的mName为"WindowedMagnification"。

2)、设置Feature的mId为FEATURE_WINDOWED_MAGNIFICATION,FEATURE_WINDOWED_MAGNIFICATION定义在DisplayAreaOrganizer中:

    /**
     * Display area that can be magnified in
     * {@link Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW}. It contains all windows
     * below {@link WindowManager.LayoutParams#TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY}.
     */
    public static final int FEATURE_WINDOWED_MAGNIFICATION = FEATURE_SYSTEM_FIRST + 4;

代表了该DisplayArea在ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW模式下可以进行放大,该DisplayArea包含了所有比TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY类型的窗口层级低的窗口,为什么这么说,继续看下面。

3)、设置Feature的mWindowLayers:

                    .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                    .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)

首先TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY代表的是一种窗口类型:

        /**
         * Window type: Window for adding accessibility window magnification above other windows.
         * This will place the window in the overlay windows.
         * @hide
         */
        public static final int TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39;

接着看下upTo方法:

            /**
             * Set that the feature applies window types that are layerd at or below the layer of
             * the given window type.
             */
            Builder upTo(int typeInclusive) {
                final int max = layerFromType(typeInclusive, false);
                for (int i = 0; i < max; i++) {
                    mLayers[i] = true;
                }
                set(typeInclusive, true);
                return this;
            }

继续看下layerFromType方法:

            private int layerFromType(int type, boolean internalWindows) {
                return mPolicy.getWindowLayerFromTypeLw(type, internalWindows);
            }

调用的是WindowManagerPolicy.getWindowLayerFromTypeLw方法:

    /**
     * Returns the layer assignment for the window type. Allows you to control how different
     * kinds of windows are ordered on-screen.
     *
     * @param type The type of window being assigned.
     * @param canAddInternalSystemWindow If the owner window associated with the type we are
     *        evaluating can add internal system windows. I.e they have
     *        {@link Manifest.permission#INTERNAL_SYSTEM_WINDOW}. If true, alert window
     *        types {@link android.view.WindowManager.LayoutParams#isSystemAlertWindowType(int)}
     *        can be assigned layers greater than the layer for
     *        {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} Else, their
     *        layers would be lesser.
     * @return int An arbitrary integer used to order windows, with lower numbers below higher ones.
     */
    default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) {
        return getWindowLayerFromTypeLw(type, canAddInternalSystemWindow,
                false /* roundedCornerOverlay */);
    }

    /**
     * Returns the layer assignment for the window type. Allows you to control how different
     * kinds of windows are ordered on-screen.
     *
     * @param type The type of window being assigned.
     * @param canAddInternalSystemWindow If the owner window associated with the type we are
     *        evaluating can add internal system windows. I.e they have
     *        {@link Manifest.permission#INTERNAL_SYSTEM_WINDOW}. If true, alert window
     *        types {@link android.view.WindowManager.LayoutParams#isSystemAlertWindowType(int)}
     *        can be assigned layers greater than the layer for
     *        {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} Else, their
     *        layers would be lesser.
     * @param roundedCornerOverlay {#code true} to indicate that the owner window is rounded corner
     *                             overlay.
     * @return int An arbitrary integer used to order windows, with lower numbers below higher ones.
     */
    default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow,
            boolean roundedCornerOverlay) {
        // Always put the rounded corner layer to the top most.
        if (roundedCornerOverlay && canAddInternalSystemWindow) {
            return getMaxWindowLayer();
        }
        if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
            return APPLICATION_LAYER;
        }

        switch (type) {
            case TYPE_WALLPAPER:
                // wallpaper is at the bottom, though the window manager may move it.
                return  1;
            case TYPE_PRESENTATION:
            case TYPE_PRIVATE_PRESENTATION:
            case TYPE_DOCK_DIVIDER:
            case TYPE_QS_DIALOG:
            case TYPE_PHONE:
                return  3;
            case TYPE_SEARCH_BAR:
            case TYPE_VOICE_INTERACTION_STARTING:
                return  4;
            case TYPE_VOICE_INTERACTION:
                // voice interaction layer is almost immediately above apps.
                return  5;
            case TYPE_INPUT_CONSUMER:
                return  6;
            case TYPE_SYSTEM_DIALOG:
                return  7;
            case TYPE_TOAST:
                // toasts and the plugged-in battery thing
                return  8;
            case TYPE_PRIORITY_PHONE:
                // SIM errors and unlock.  Not sure if this really should be in a high layer.
                return  9;
            case TYPE_SYSTEM_ALERT:
                // like the ANR / app crashed dialogs
                // Type is deprecated for non-system apps. For system apps, this type should be
                // in a higher layer than TYPE_APPLICATION_OVERLAY.
                return  canAddInternalSystemWindow ? 13 : 10;
            case TYPE_APPLICATION_OVERLAY:
                return  12;
            case TYPE_INPUT_METHOD:
                // on-screen keyboards and other such input method user interfaces go here.
                return  15;
            case TYPE_INPUT_METHOD_DIALOG:
                // on-screen keyboards and other such input method user interfaces go here.
                return  16;
            case TYPE_STATUS_BAR:
                return  17;
            case TYPE_STATUS_BAR_ADDITIONAL:
                return  18;
            case TYPE_NOTIFICATION_SHADE:
                return  19;
            case TYPE_STATUS_BAR_SUB_PANEL:
                return  20;
            case TYPE_KEYGUARD_DIALOG:
                return  21;
            case TYPE_VOLUME_OVERLAY:
                // the on-screen volume indicator and controller shown when the user
                // changes the device volume
                return  22;
            case TYPE_SYSTEM_OVERLAY:
                // the on-screen volume indicator and controller shown when the user
                // changes the device volume
                return  canAddInternalSystemWindow ? 23 : 11;
            case TYPE_NAVIGATION_BAR:
                // the navigation bar, if available, shows atop most things
                return  24;
            case TYPE_NAVIGATION_BAR_PANEL:
                // some panels (e.g. search) need to show on top of the navigation bar
                return  25;
            case TYPE_SCREENSHOT:
                // screenshot selection layer shouldn't go above system error, but it should cover
                // navigation bars at the very least.
                return  26;
            case TYPE_SYSTEM_ERROR:
                // system-level error dialogs
                return  canAddInternalSystemWindow ? 27 : 10;
            case TYPE_MAGNIFICATION_OVERLAY:
                // used to highlight the magnified portion of a display
                return  28;
            case TYPE_DISPLAY_OVERLAY:
                // used to simulate secondary display devices
                return  29;
            case TYPE_DRAG:
                // the drag layer: input for drag-and-drop is associated with this window,
                // which sits above all other focusable windows
                return  30;
            case TYPE_ACCESSIBILITY_OVERLAY:
                // overlay put by accessibility services to intercept user interaction
                return  31;
            case TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY:
                return 32;
            case TYPE_SECURE_SYSTEM_OVERLAY:
                return  33;
            case TYPE_BOOT_PROGRESS:
                return  34;
            case TYPE_POINTER:
                // the (mouse) pointer layer
                return  35;
            default:
                Slog.e("WindowManager", "Unknown window type: " + type);
                return 3;
        }
    }

这个方法返回给定窗口类型对应的层级值。允许你控制不同类型的窗口在屏幕上的排序方式。

看方法内容很简单,对每一种类型的窗口,都规定了一个层级值。层级值反映了这些窗口在Z轴上的排序方式,层级值越高在Z轴上的位置也就越高。但是层级值的大小和窗口类型对应的那个值的大小并没有关系,窗口类型值大的窗口,对应的层级值不一定大。

另外,大部分层级值都唯一对应一种窗口类型,比较特殊的是:

  • 层级值2,所有App窗口会被归类到这一个层级。
  • 层级值3,该方法中没有提到的窗口类型会被归类到这一个层级。

知道了这些内容再回头看upTo方法,就很容易理解了:

首先找到TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY这个窗口类型对应的层级值,也就是32,接着将mLayers数组从0到32的元素,全部赋值为true。

看下Feature.mBuilder的成员变量mLayers的定义:

        static class Builder {
            // ......
            private final boolean[] mLayers;
            // ......

            /**
             * Builds a new feature that applies to a set of window types as specified by the
             * builder methods.
             *
             * <p>The set of types is updated iteratively in the order of the method invocations.
             * For example, {@code all().except(TYPE_STATUS_BAR)} expresses that a feature should
             * apply to all types except TYPE_STATUS_BAR.
             *
             * <p>The builder starts out with the feature not applying to any types.
             *
             * @param name the name of the feature.
             * @param id of the feature. {@see Feature#getId}
             */
            Builder(WindowManagerPolicy policy, String name, int id) {
                mPolicy = policy;
                mName = name;
                mId = id;
                mLayers = new boolean[mPolicy.getMaxWindowLayer() + 1];
            }
            
            // ......
        }

WindowManagerPolicy.getMaxWindowLayer方法是:

    // TODO(b/155340867): consider to remove the logic after using pure Surface for rounded corner
    //  overlay.
    /**
     * Returns the max window layer.
     * <p>Note that the max window layer should be higher that the maximum value which reported
     * by {@link #getWindowLayerFromTypeLw(int, boolean)} to contain rounded corner overlay.</p>
     *
     * @see WindowManager.LayoutParams#PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY
     */
    default int getMaxWindowLayer() {
        return 36;
    }

返回了目前WindowManagerPolicy定义的最大层级值,36。

那么Feature.Builder.mLayers数组初始化为:

mLayers = new boolean[37];

Feature.mWindowLayers则是在Feature.Builder.build方法中完全由Feature.Builder.mLayers的值复制过来:

            Feature build() {
                if (mExcludeRoundedCorner) {
                    // Always put the rounded corner layer to the top most layer.
                    mLayers[mPolicy.getMaxWindowLayer()] = false;
                }
                return new Feature(mName, mId, mLayers.clone(), mNewDisplayAreaSupplier);
            }

将Feature.Builde.mLayer数组中的每个元素设置为true的意思是什么呢?打个比方,将Feature.Builde.mLayer[32]设置为true,后续调用Feature.Builder.build后,Feature.mWindowLayers[32]也会被设置true。而Feature.mWindowLayers[32]为true,则表示该Feature对应的DisplayArea,可以包含层级值为32,也就是窗口类型为TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY的窗口。

另外目前看到mExcludeRoundedCorner是始终为true的,也就是说,mLayers[36]始终为false。

看下都有哪些方法来设置Feature.Builde.mLayer:

            /**
             * Set that the feature applies to all window types.
             */
            Builder all() {
                Arrays.fill(mLayers, true);
                return this;
            }

            /**
             * Set that the feature applies to the given window types.
             */
            Builder and(int... types) {
                for (int i = 0; i < types.length; i++) {
                    int type = types[i];
                    set(type, true);
                }
                return this;
            }

            /**
             * Set that the feature does not apply to the given window types.
             */
            Builder except(int... types) {
                for (int i = 0; i < types.length; i++) {
                    int type = types[i];
                    set(type, false);
                }
                return this;
            }

            /**
             * Set that the feature applies window types that are layerd at or below the layer of
             * the given window type.
             */
            Builder upTo(int typeInclusive) {
                final int max = layerFromType(typeInclusive, false);
                for (int i = 0; i < max; i++) {
                    mLayers[i] = true;
                }
                set(typeInclusive, true);
                return this;
            }
  • all,将mLayers数组中的所有元素都设置为true,表示当前DisplayArea可以包含所有类型的窗口。
  • and,先将传入的窗口类型先转换为对应的层级值,然后将mLayers数组中与该层级值对应的元素设置为true,表示该DisplayArea可以包含传入的窗口类型对应的窗口。
  • except,先将传入的窗口类型先转换为对应的层级值,然后将mLayers数组中与该层级值对应的元素设置为false,表示该DisplayArea不再包含传入的窗口类型对应的窗口。
  • upTo,先将传入的窗口类型先转换为对应的层级值,然后将mLayers数组中与该层级值对应的的元素之前的所有元素(包含该元素)设置为true,表示当前DisplayArea可以包含比传入的窗口类型层级值低的所有窗口。

最后,总结一下这一节的内容。

            rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",
                    FEATURE_WINDOWED_MAGNIFICATION)
                    .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                    .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                    // Make the DA dimmable so that the magnify window also mirrors the dim layer.
                    .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
                    .build());

以上代码,为HierarchyBuilder添加了一个Feature,Feature名字是"WindowedMagnification",ID为FEATURE_WINDOWED_MAGNIFICATION,符合这个Feature的DisplayArea可以包含层级值为0~31的窗口。

后续添加其他的Feature和这个WindowedMagnification类似,将指定的窗口类型转换为层级值,可以得到:

Feature.mName Feature.mID Feature.mWindowLayers
WindowedMagnification FEATURE_WINDOWED_MAGNIFICATION 0~31
HideDisplayCutout FEATURE_HIDE_DISPLAY_CUTOUT 016,18,2023,26~35
OneHandedBackgroundPanel FEATURE_ONE_HANDED_BACKGROUND_PANEL 0~1
OneHanded FEATURE_ONE_HANDED 023,2635
FullscreenMagnification FEATURE_FULLSCREEN_MAGNIFICATION 014,1723,2627,2931,33~35
ImePlaceholder FEATURE_IME_PLACEHOLDER 15~16

2.2.5 生成DisplayArea层级结构

            // Instantiate the policy with the hierarchy defined above. This will create and attach
            // all the necessary DisplayAreas to the root.
            return new DisplayAreaPolicyBuilder().setRootHierarchy(rootHierarchy).build(wmService);

先调用DisplayAreaPolicyBuilder.setRootHierarchy将上面创建的HierarchyBuilder对象保存在DisplayAreaPolicyBuilder的成员变量mRootHierarchyBuilder中。

    /** Defines the root hierarchy for the whole logical display. */
    DisplayAreaPolicyBuilder setRootHierarchy(HierarchyBuilder rootHierarchyBuilder) {
        mRootHierarchyBuilder = rootHierarchyBuilder;
        return this;
    }

最后调用了DisplayAreaPolicyBuilder.build方法去生成了一个DisplayArea层级结构。

    Result build(WindowManagerService wmService) {
        validate();

        // Attach DA group roots to screen hierarchy before adding windows to group hierarchies.
        mRootHierarchyBuilder.build(mDisplayAreaGroupHierarchyBuilders);
        List<RootDisplayArea> displayAreaGroupRoots = new ArrayList<>(
                mDisplayAreaGroupHierarchyBuilders.size());
        for (int i = 0; i < mDisplayAreaGroupHierarchyBuilders.size(); i++) {
            HierarchyBuilder hierarchyBuilder = mDisplayAreaGroupHierarchyBuilders.get(i);
            hierarchyBuilder.build();
            displayAreaGroupRoots.add(hierarchyBuilder.mRoot);
        }
        // Use the default function if it is not specified otherwise.
        if (mSelectRootForWindowFunc == null) {
            mSelectRootForWindowFunc = new DefaultSelectRootForWindowFunction(
                    mRootHierarchyBuilder.mRoot, displayAreaGroupRoots);
        }
        return new Result(wmService, mRootHierarchyBuilder.mRoot, displayAreaGroupRoots,
                mSelectRootForWindowFunc);
    }

这里调用了HierarchyBuilder.build去生成DisplayArea层级结构,并且有一个传参mDisplayAreaGroupHierarchyBuilders。目前我看到对于mDisplayAreaGroupHierarchyBuilders来说,没有添加子元素的地方,因此传入的mDisplayAreaGroupHierarchyBuilders是一个空的列表,接着分析HierarchyBuilder.build。

2.3 DisplayAreaPolicyBuilder.HierarchyBuilder.build

        /**
         * Builds the {@link DisplayArea} hierarchy below root. And adds the roots of those
         * {@link HierarchyBuilder} as children.
         */
        private void build(@Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders) {
            final WindowManagerPolicy policy = mRoot.mWmService.mPolicy;
            final int maxWindowLayerCount = policy.getMaxWindowLayer() + 1;
            final DisplayArea.Tokens[] displayAreaForLayer =
                    new DisplayArea.Tokens[maxWindowLayerCount];
            final Map<Feature, List<DisplayArea<WindowContainer>>> featureAreas =
                    new ArrayMap<>(mFeatures.size());
            for (int i = 0; i < mFeatures.size(); i++) {
                featureAreas.put(mFeatures.get(i), new ArrayList<>());
            }

            // This method constructs the layer hierarchy with the following properties:
            // (1) Every feature maps to a set of DisplayAreas
            // (2) After adding a window, for every feature the window's type belongs to,
            //     it is a descendant of one of the corresponding DisplayAreas of the feature.
            // (3) Z-order is maintained, i.e. if z-range(area) denotes the set of layers of windows
            //     within a DisplayArea:
            //      for every pair of DisplayArea siblings (a,b), where a is below b, it holds that
            //      max(z-range(a)) <= min(z-range(b))
            //
            // The algorithm below iteratively creates such a hierarchy:
            //  - Initially, all windows are attached to the root.
            //  - For each feature we create a set of DisplayAreas, by looping over the layers
            //    - if the feature does apply to the current layer, we need to find a DisplayArea
            //      for it to satisfy (2)
            //      - we can re-use the previous layer's area if:
            //         the current feature also applies to the previous layer, (to satisfy (3))
            //         and the last feature that applied to the previous layer is the same as
            //           the last feature that applied to the current layer (to satisfy (2))
            //      - otherwise we create a new DisplayArea below the last feature that applied
            //        to the current layer

            PendingArea[] areaForLayer = new PendingArea[maxWindowLayerCount];
            final PendingArea root = new PendingArea(null, 0, null);
            Arrays.fill(areaForLayer, root);

            // Create DisplayAreas to cover all defined features.
            final int size = mFeatures.size();
            for (int i = 0; i < size; i++) {
                // Traverse the features with the order they are defined, so that the early defined
                // feature will be on the top in the hierarchy.
                final Feature feature = mFeatures.get(i);
                PendingArea featureArea = null;
                for (int layer = 0; layer < maxWindowLayerCount; layer++) {
                    if (feature.mWindowLayers[layer]) {
                        // This feature will be applied to this window layer.
                        //
                        // We need to find a DisplayArea for it:
                        // We can reuse the existing one if it was created for this feature for the
                        // previous layer AND the last feature that applied to the previous layer is
                        // the same as the feature that applied to the current layer (so they are ok
                        // to share the same parent DisplayArea).
                        if (featureArea == null || featureArea.mParent != areaForLayer[layer]) {
                            // No suitable DisplayArea:
                            // Create a new one under the previous area (as parent) for this layer.
                            featureArea = new PendingArea(feature, layer, areaForLayer[layer]);
                            areaForLayer[layer].mChildren.add(featureArea);
                        }
                        areaForLayer[layer] = featureArea;
                    } else {
                        // This feature won't be applied to this window layer. If it needs to be
                        // applied to the next layer, we will need to create a new DisplayArea for
                        // that.
                        featureArea = null;
                    }
                }
            }

            // Create Tokens as leaf for every layer.
            PendingArea leafArea = null;
            int leafType = LEAF_TYPE_TOKENS;
            for (int layer = 0; layer < maxWindowLayerCount; layer++) {
                int type = typeOfLayer(policy, layer);
                // Check whether we can reuse the same Tokens with the previous layer. This happens
                // if the previous layer is the same type as the current layer AND there is no
                // feature that applies to only one of them.
                if (leafArea == null || leafArea.mParent != areaForLayer[layer]
                        || type != leafType) {
                    // Create a new Tokens for this layer.
                    leafArea = new PendingArea(null /* feature */, layer, areaForLayer[layer]);
                    areaForLayer[layer].mChildren.add(leafArea);
                    leafType = type;
                    if (leafType == LEAF_TYPE_TASK_CONTAINERS) {
                        // We use the passed in TaskDisplayAreas for task container type of layer.
                        // Skip creating Tokens even if there is no TDA.
                        addTaskDisplayAreasToApplicationLayer(areaForLayer[layer]);
                        addDisplayAreaGroupsToApplicationLayer(areaForLayer[layer],
                                displayAreaGroupHierarchyBuilders);
                        leafArea.mSkipTokens = true;
                    } else if (leafType == LEAF_TYPE_IME_CONTAINERS) {
                        // We use the passed in ImeContainer for ime container type of layer.
                        // Skip creating Tokens even if there is no ime container.
                        leafArea.mExisting = mImeContainer;
                        leafArea.mSkipTokens = true;
                    }
                }
                leafArea.mMaxLayer = layer;
            }
            root.computeMaxLayer();

            // We built a tree of PendingAreas above with all the necessary info to represent the
            // hierarchy, now create and attach real DisplayAreas to the root.
            root.instantiateChildren(mRoot, displayAreaForLayer, 0, featureAreas);

            // Notify the root that we have finished attaching all the DisplayAreas. Cache all the
            // feature related collections there for fast access.
            mRoot.onHierarchyBuilt(mFeatures, displayAreaForLayer, featureAreas);
        }

这个方法虽然很长,但是明显可以分成几部分来看。

2.3.1 PendingArea数组

            final WindowManagerPolicy policy = mRoot.mWmService.mPolicy;
            final int maxWindowLayerCount = policy.getMaxWindowLayer() + 1;
            final DisplayArea.Tokens[] displayAreaForLayer =
                    new DisplayArea.Tokens[maxWindowLayerCount];
            final Map<Feature, List<DisplayArea<WindowContainer>>> featureAreas =
                    new ArrayMap<>(mFeatures.size());
            for (int i = 0; i < mFeatures.size(); i++) {
                featureAreas.put(mFeatures.get(i), new ArrayList<>());
            }

            // This method constructs the layer hierarchy with the following properties:
            // (1) Every feature maps to a set of DisplayAreas
            // (2) After adding a window, for every feature the window's type belongs to,
            //     it is a descendant of one of the corresponding DisplayAreas of the feature.
            // (3) Z-order is maintained, i.e. if z-range(area) denotes the set of layers of windows
            //     within a DisplayArea:
            //      for every pair of DisplayArea siblings (a,b), where a is below b, it holds that
            //      max(z-range(a)) <= min(z-range(b))
            //
            // The algorithm below iteratively creates such a hierarchy:
            //  - Initially, all windows are attached to the root.
            //  - For each feature we create a set of DisplayAreas, by looping over the layers
            //    - if the feature does apply to the current layer, we need to find a DisplayArea
            //      for it to satisfy (2)
            //      - we can re-use the previous layer's area if:
            //         the current feature also applies to the previous layer, (to satisfy (3))
            //         and the last feature that applied to the previous layer is the same as
            //           the last feature that applied to the current layer (to satisfy (2))
            //      - otherwise we create a new DisplayArea below the last feature that applied
            //        to the current layer

            PendingArea[] areaForLayer = new PendingArea[maxWindowLayerCount];
            final PendingArea root = new PendingArea(null, 0, null);
            Arrays.fill(areaForLayer, root);

1)、maxWindowLayerCount根据我们之前的分析,为37,目前我们定义的窗口层级值为0~36。

2)、创建了一个大小为37的PendingArea数组:

PendingArea[] areaForLayer = new PendingArea[maxWindowLayerCount];

创建了一个PendingArea对象,填充到areaForLayer数组中:

            final PendingArea root = new PendingArea(null, 0, null);
            Arrays.fill(areaForLayer, root);

PendingArea对象定义在DisplayAreaPolicyBuilder中:

    static class PendingArea {
        final int mMinLayer;
        final ArrayList<PendingArea> mChildren = new ArrayList<>();
        final Feature mFeature;
        final PendingArea mParent;
        int mMaxLayer;

我们正在分析的这个方法,就是首先要生成一个PendingArea树,然后根据这个PendingArea树去生成一个DisplayArea树,一个PendingArea对应着一个DisplayArea:

  • PendingArea是一个树节点的话,那么PendingArea的mParent则代表当前节点的父节点,mChildren则表示的是当前节点的子节点。

  • mFeature对应的则是这个PendingArea的特征。

  • mMinLayer和mMaxLayer代表的是当前PendingArea可以容纳的窗口层级值的一个范围。

为了接下来的分析,根据PendingArea的成员变量,可以将PendingArea表述为以下形式:

mFeature.mName:mMinLayer:mMaxLayer

比如,“OneHandedBackgroundPanel:0:1”,表示名为OneHandedBackgroundPanel的PendingArea,可以容纳层级值从0到1的窗口。

root现在没有一个Feature,因此名字暂时认为是Root,此时为“Root:0:0”。

那么areaForLayer数组,初始情况为:

areaForLayer[37] 初始
areaForLayer[0] Root:0:0
areaForLayer[1] Root:0:0
areaForLayer[2] Root:0:0
areaForLayer[3] Root:0:0
areaForLayer[4] Root:0:0
areaForLayer[5] Root:0:0
areaForLayer[6] Root:0:0
areaForLayer[7] Root:0:0
areaForLayer[8] Root:0:0
areaForLayer[9] Root:0:0
areaForLayer[10] Root:0:0
areaForLayer[11] Root:0:0
areaForLayer[12] Root:0:0
areaForLayer[13] Root:0:0
areaForLayer[14] Root:0:0
areaForLayer[15] Root:0:0
areaForLayer[16] Root:0:0
areaForLayer[17] Root:0:0
areaForLayer[18] Root:0:0
areaForLayer[19] Root:0:0
areaForLayer[20] Root:0:0
areaForLayer[21] Root:0:0
areaForLayer[22] Root:0:0
areaForLayer[23] Root:0:0
areaForLayer[24] Root:0:0
areaForLayer[25] Root:0:0
areaForLayer[26] Root:0:0
areaForLayer[27] Root:0:0
areaForLayer[28] Root:0:0
areaForLayer[29] Root:0:0
areaForLayer[30] Root:0:0
areaForLayer[31] Root:0:0
areaForLayer[32] Root:0:0
areaForLayer[33] Root:0:0
areaForLayer[34] Root:0:0
areaForLayer[35] Root:0:0
areaForLayer[36] Root:0:0

2.3.2 PendingArea数组的生成

            // Create DisplayAreas to cover all defined features.
            final int size = mFeatures.size();
            for (int i = 0; i < size; i++) {
                // Traverse the features with the order they are defined, so that the early defined
                // feature will be on the top in the hierarchy.
                final Feature feature = mFeatures.get(i);
                PendingArea featureArea = null;
                for (int layer = 0; layer < maxWindowLayerCount; layer++) {
                    if (feature.mWindowLayers[layer]) {
                        // This feature will be applied to this window layer.
                        //
                        // We need to find a DisplayArea for it:
                        // We can reuse the existing one if it was created for this feature for the
                        // previous layer AND the last feature that applied to the previous layer is
                        // the same as the feature that applied to the current layer (so they are ok
                        // to share the same parent DisplayArea).
                        if (featureArea == null || featureArea.mParent != areaForLayer[layer]) {
                            // No suitable DisplayArea:
                            // Create a new one under the previous area (as parent) for this layer.
                            featureArea = new PendingArea(feature, layer, areaForLayer[layer]);
                            areaForLayer[layer].mChildren.add(featureArea);
                        }
                        areaForLayer[layer] = featureArea;
                    } else {
                        // This feature won't be applied to this window layer. If it needs to be
                        // applied to the next layer, we will need to create a new DisplayArea for
                        // that.
                        featureArea = null;
                    }
                }
            }

针对每一种Feature,都会走一次流程,根据2.2.4可知,mFeatures中有6个Feature,并且Feature添加到HierarchyBuilder的顺序,其实已经代表了这几种Feature对应的DisplayArea的层级高低。

Feature.mName Feature.mID Feature.mWindowLayers
WindowedMagnification FEATURE_WINDOWED_MAGNIFICATION 0~31
HideDisplayCutout FEATURE_HIDE_DISPLAY_CUTOUT 016,18,2023,26~35
OneHandedBackgroundPanel FEATURE_ONE_HANDED_BACKGROUND_PANEL 0~1
OneHanded FEATURE_ONE_HANDED 023,2635
FullscreenMagnification FEATURE_FULLSCREEN_MAGNIFICATION 014,1723,2627,2931,33~35
ImePlaceholder FEATURE_IME_PLACEHOLDER 15~16

2.3.2.1 WindowedMagnification

先看WindowedMagnification。

1)、layer为0,此时feature.mWindowLayers[0]为true,featureArea为null,那么创建一个PendingArea对象,“WindowedMagnification:0:0”,这个新创建的“WindowedMagnification:0:0“,parent为”Root:0:0“,并且将这个新创建的“WindowedMagnification:0:0“添加到”Root:0:0“的子节点中,最后将areaForLayer[0]指向这个新创建的“WindowedMagnification:0:0”。

2)、layer为1,此时feature.mWindowLayers[1]为true,featureArea为“WindowedMagnification:0:0”,featureArea.mParent为”Root:0:0“,areaForLayer[1]也是”Root:0:0“,那么不创建PendingArea对象,将areaForLayer[1]指向“WindowedMagnification:0:0”。

3)、后续直到layer为32之前,都是如此。当layer为32时,feature.mWindowLayers[32]为false,不会走到这些逻辑中。

那么经过第一轮循环,areaForLayer数组的情况是:

areaForLayer[37] 初始 WindowedMagnification
areaForLayer[0] Root:0:0 WindowedMagnification:0:31
areaForLayer[1] Root:0:0 WindowedMagnification:0:31
areaForLayer[2] Root:0:0 WindowedMagnification:0:31
areaForLayer[3] Root:0:0 WindowedMagnification:0:31
areaForLayer[4] Root:0:0 WindowedMagnification:0:31
areaForLayer[5] Root:0:0 WindowedMagnification:0:31
areaForLayer[6] Root:0:0 WindowedMagnification:0:31
areaForLayer[7] Root:0:0 WindowedMagnification:0:31
areaForLayer[8] Root:0:0 WindowedMagnification:0:31
areaForLayer[9] Root:0:0 WindowedMagnification:0:31
areaForLayer[10] Root:0:0 WindowedMagnification:0:31
areaForLayer[11] Root:0:0 WindowedMagnification:0:31
areaForLayer[12] Root:0:0 WindowedMagnification:0:31
areaForLayer[13] Root:0:0 WindowedMagnification:0:31
areaForLayer[14] Root:0:0 WindowedMagnification:0:31
areaForLayer[15] Root:0:0 WindowedMagnification:0:31
areaForLayer[16] Root:0:0 WindowedMagnification:0:31
areaForLayer[17] Root:0:0 WindowedMagnification:0:31
areaForLayer[18] Root:0:0 WindowedMagnification:0:31
areaForLayer[19] Root:0:0 WindowedMagnification:0:31
areaForLayer[20] Root:0:0 WindowedMagnification:0:31
areaForLayer[21] Root:0:0 WindowedMagnification:0:31
areaForLayer[22] Root:0:0 WindowedMagnification:0:31
areaForLayer[23] Root:0:0 WindowedMagnification:0:31
areaForLayer[24] Root:0:0 WindowedMagnification:0:31
areaForLayer[25] Root:0:0 WindowedMagnification:0:31
areaForLayer[26] Root:0:0 WindowedMagnification:0:31
areaForLayer[27] Root:0:0 WindowedMagnification:0:31
areaForLayer[28] Root:0:0 WindowedMagnification:0:31
areaForLayer[29] Root:0:0 WindowedMagnification:0:31
areaForLayer[30] Root:0:0 WindowedMagnification:0:31
areaForLayer[31] Root:0:0 WindowedMagnification:0:31
areaForLayer[32] Root:0:0
areaForLayer[33] Root:0:0
areaForLayer[34] Root:0:0
areaForLayer[35] Root:0:0
areaForLayer[36] Root:0:0

转换为树状图:

image

2.3.2.1 HideDisplayCutout

1)、layer为0,此时feature.mWindowLayers[0]为true,featureArea为null,那么创建一个PendingArea对象,“HideDisplayCutout:0:0”,这个新创建的“HideDisplayCutout:0:0“,parent为areaForLayer[0],但是经过第一步,areaForLayer[0]此时已经从"Root:0:0"被替换为了”WindowedMagnification:0:0“。接着将这个新创建的“HideDisplayCutout:0:0“添加到”WindowedMagnification:0:0“的子节点中,最后将areaForLayer[0]指向这个新创建的“HideDisplayCutout:0:0”。

2)、layer为1,此时feature.mWindowLayers[1]为true,featureArea为“HideDisplayCutout:0:0”,featureArea.mParent为”WindowedMagnification:0:0“,areaForLayer[1]也是”WindowedMagnification:0:0“,那么不创建PendingArea对象,将areaForLayer[1]指向“HideDisplayCutout:0:0”。

3)、后续直到layer为16,都是如此。

4)、layer为17,此时feature.mWindowLayers[17]为false,将featureArea重置为null。

5)、layer为18,此时feature.mWindowLayers[18]为true,重新创建了一个PendingArea:”HideDisplayCutout:18:0“,接着将这个新创建的“HideDisplayCutout:18:0“添加到”WindowedMagnification:0:0“的子节点中,最后将areaForLayer[18]指向这个新创建的“HideDisplayCutout:18:0”。

6)、layer为19,此时feature.mWindowLayers[19]为false,将featureArea重置为null。

7)、laye为20,此时feature.mWindowLayers[20]为true,重新创建了一个PendingArea:”HideDisplayCutout:20:0“,接着将这个新创建的“HideDisplayCutout:20:0“添加到”WindowedMagnification:0:0“的子节点中,最后将areaForLayer[20]指向这个新创建的“HideDisplayCutout:20:0”。

8)、后续直到layer为23,都是复用的”HideDisplayCutout:20:0“。

9)、layer为24,此时feature.mWindowLayers[24]为false,将featureArea重置为null。

10)、layer为25,此时feature.mWindowLayers[25]为false,将featureArea重置为null。

11)、layer为26,此时feature.mWindowLayers[26]为true,重新创建了一个PendingArea:”HideDisplayCutout:26:0“,接着将这个新创建的“HideDisplayCutout:26:0“添加到”WindowedMagnification:0:0“的子节点中,最后将areaForLayer[26]指向这个新创建的“HideDisplayCutout:26:0”。

12)、直到layer为31,都是复用的”HideDisplayCutout:26:0“。

13)、layer为32,此时feature.mWindowLayers[32]为true,此时featureArea为“HideDisplayCutout:26:0“,parent为”WindowedMagnification:0:0“,但是此时areaForLayer[32]是”Root:0:0“,那么此时会重新创建一个PendingArea:“HideDisplayCutout:32:0“,接着将这个新创建的“HideDisplayCutout:32:0“添加到”Root:0:0“的子节点中,最后将areaForLayer[32]指向这个新创建的“HideDisplayCutout:32:0”。

14)、后续直到layer为36,都是复用的“HideDisplayCutout:32:”。

那么经过第一轮循环,areaForLayer数组的情况是:

areaForLayer[37] 初始 WindowedMagnification HideDisplayCutout
areaForLayer[0] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[1] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[2] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[3] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[4] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[5] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[6] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[7] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[8] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[9] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[10] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[11] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[12] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[13] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[14] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[15] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[16] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0
areaForLayer[17] Root:0:0 WindowedMagnification:0:0
areaForLayer[18] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:18:0
areaForLayer[19] Root:0:0 WindowedMagnification:0:0
areaForLayer[20] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:20:0
areaForLayer[21] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:20:0
areaForLayer[22] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:20:0
areaForLayer[23] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:20:0
areaForLayer[24] Root:0:0 WindowedMagnification:0:0
areaForLayer[25] Root:0:0 WindowedMagnification:0:0
areaForLayer[26] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0
areaForLayer[27] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0
areaForLayer[28] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0
areaForLayer[29] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0
areaForLayer[30] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0
areaForLayer[31] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0
areaForLayer[32] Root:0:0 HideDisplayCutout:32:0
areaForLayer[33] Root:0:0 HideDisplayCutout:32:0
areaForLayer[34] Root:0:0 HideDisplayCutout:32:0
areaForLayer[35] Root:0:0 HideDisplayCutout:32:0
areaForLayer[36] Root:0:0

转换为树状图:

image

2.3.2.3 最终结果

后续的分析类似,不再赘述,最终的结果是:

areaForLayer[37] 初始 WindowedMagnification HideDisplayCutout OneHandedBackgroundPanel OneHanded FullscreenMagnification ImePlaceholder
areaForLayer[0] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHandedBackgroundPanel:0:0 OneHanded:0:0 FullscreenMagnification:0:0
areaForLayer[1] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHandedBackgroundPanel:0:0 OneHanded:0:0 FullscreenMagnification:0:0
areaForLayer[2] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0
areaForLayer[3] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0
areaForLayer[4] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0
areaForLayer[5] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0
areaForLayer[6] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0
areaForLayer[7] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0
areaForLayer[8] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0
areaForLayer[9] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0
areaForLayer[10] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0
areaForLayer[11] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0
areaForLayer[12] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0
areaForLayer[13] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0
areaForLayer[14] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0
areaForLayer[15] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 ImePlaceholder:15:0
areaForLayer[16] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 ImePlaceholder:15:0
areaForLayer[17] Root:0:0 WindowedMagnification:0:0 OneHanded:17:0 FullscreenMagnification:17:0
areaForLayer[18] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:18:0 OneHanded:18:0 FullscreenMagnification:18:0
areaForLayer[19] Root:0:0 WindowedMagnification:0:0 OneHanded:19:0 FullscreenMagnification:19:0
areaForLayer[20] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:20:0 OneHanded:20:0 FullscreenMagnification:20:0
areaForLayer[21] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:20:0 OneHanded:20:0 FullscreenMagnification:20:0
areaForLayer[22] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:20:0 OneHanded:20:0 FullscreenMagnification:20:0
areaForLayer[23] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:20:0 OneHanded:20:0 FullscreenMagnification:20:0
areaForLayer[24] Root:0:0 WindowedMagnification:0:0
areaForLayer[25] Root:0:0 WindowedMagnification:0:0
areaForLayer[26] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0 OneHanded:26:0 FullscreenMagnification:26:0
areaForLayer[27] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0 OneHanded:26:0 FullscreenMagnification:26:0
areaForLayer[28] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0 OneHanded:26:0
areaForLayer[29] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0 OneHanded:26:0 FullscreenMagnification:29:0
areaForLayer[30] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0 OneHanded:26:0 FullscreenMagnification:29:0
areaForLayer[31] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0 OneHanded:26:0 FullscreenMagnification:29:0
areaForLayer[32] Root:0:0 HideDisplayCutout:32:0 OneHanded:32:0
areaForLayer[33] Root:0:0 HideDisplayCutout:32:0 OneHanded:32:0 FullscreenMagnification:33:0
areaForLayer[34] Root:0:0 HideDisplayCutout:32:0 OneHanded:32:0 FullscreenMagnification:33:0
areaForLayer[35] Root:0:0 HideDisplayCutout:32:0 OneHanded:32:0 FullscreenMagnification:33:0
areaForLayer[36] Root:0:0

转换为树状图:

image

2.3.3 为PendingArea数组添加Leaf

            // Create Tokens as leaf for every layer.
            PendingArea leafArea = null;
            int leafType = LEAF_TYPE_TOKENS;
            for (int layer = 0; layer < maxWindowLayerCount; layer++) {
                int type = typeOfLayer(policy, layer);
                // Check whether we can reuse the same Tokens with the previous layer. This happens
                // if the previous layer is the same type as the current layer AND there is no
                // feature that applies to only one of them.
                if (leafArea == null || leafArea.mParent != areaForLayer[layer]
                        || type != leafType) {
                    // Create a new Tokens for this layer.
                    leafArea = new PendingArea(null /* feature */, layer, areaForLayer[layer]);
                    areaForLayer[layer].mChildren.add(leafArea);
                    leafType = type;
                    if (leafType == LEAF_TYPE_TASK_CONTAINERS) {
                        // We use the passed in TaskDisplayAreas for task container type of layer.
                        // Skip creating Tokens even if there is no TDA.
                        addTaskDisplayAreasToApplicationLayer(areaForLayer[layer]);
                        addDisplayAreaGroupsToApplicationLayer(areaForLayer[layer],
                                displayAreaGroupHierarchyBuilders);
                        leafArea.mSkipTokens = true;
                    } else if (leafType == LEAF_TYPE_IME_CONTAINERS) {
                        // We use the passed in ImeContainer for ime container type of layer.
                        // Skip creating Tokens even if there is no ime container.
                        leafArea.mExisting = mImeContainer;
                        leafArea.mSkipTokens = true;
                    }
                }
                leafArea.mMaxLayer = layer;
            }

这个方法比上面的那个简单,继续往PendingArea层级结构向下添加leafArea,最后设置了leafArea的mMaxLayer。

Leaf有3种:

        private static final int LEAF_TYPE_TASK_CONTAINERS = 1;
        private static final int LEAF_TYPE_IME_CONTAINERS = 2;
        private static final int LEAF_TYPE_TOKENS = 0;

根据Leaf的父节点的层级值得到:

        private static int typeOfLayer(WindowManagerPolicy policy, int layer) {
            if (layer == APPLICATION_LAYER) {
                return LEAF_TYPE_TASK_CONTAINERS;
            } else if (layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD)
                    || layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD_DIALOG)) {
                return LEAF_TYPE_IME_CONTAINERS;
            } else {
                return LEAF_TYPE_TOKENS;
            }
        }

总结为:

  • 层级值为APPLICATION_LAYER,即2,Leaf的类型为LEAF_TYPE_TASK_CONTAINERS。
  • 层级值为15,16,Leaf的类型为LEAF_TYPE_IME_CONTAINERS。
  • 其他层级值对应的Leaf类型为LEAF_TYPE_TOKENS。

看一下这里针对LEAF_TYPE_TASK_CONTAINERS和LEAF_TYPE_IME_CONTAINERS做的特殊处理:

1)、LEAF_TYPE_TASK_CONTAINERS

                    if (leafType == LEAF_TYPE_TASK_CONTAINERS) {
                        // We use the passed in TaskDisplayAreas for task container type of layer.
                        // Skip creating Tokens even if there is no TDA.
                        addTaskDisplayAreasToApplicationLayer(areaForLayer[layer]);
                        addDisplayAreaGroupsToApplicationLayer(areaForLayer[layer],
                                displayAreaGroupHierarchyBuilders);
                        leafArea.mSkipTokens = true;
                    }

根据之前的分析,我们知道displayAreaGroupHierarchyBuilders是一个空的列表,所以只看addTaskDisplayAreasToApplicationLayer方法。

        /** Adds all {@link TaskDisplayArea} to the application layer. */
        private void addTaskDisplayAreasToApplicationLayer(PendingArea parentPendingArea) {
            final int count = mTaskDisplayAreas.size();
            for (int i = 0; i < count; i++) {
                PendingArea leafArea =
                        new PendingArea(null /* feature */, APPLICATION_LAYER, parentPendingArea);
                leafArea.mExisting = mTaskDisplayAreas.get(i);
                leafArea.mMaxLayer = APPLICATION_LAYER;
                parentPendingArea.mChildren.add(leafArea);
            }
        }

根据2.2.3可知,此时的mTaskDisplayAreas中只有一个元素,即名为”DefaultTaskDisplayArea“的TaskDisplayArea对象,这里是为该对象创建了一个对应的PendingArea对象,并且将创建的PendingArea添加到areaForLayer[2]节点之下,然后将PendingArea.mExisting设置为true

        /** If not {@code null}, use this instead of creating a {@link DisplayArea.Tokens}. */
        @Nullable DisplayArea mExisting;

那么后续根据PendingArea生成DisplayArea.Tokens的时候,如果mExisting不为空,那么直接用mExisting,而不会再重新创建一个DisplayArea.Tokens对象。

另外这里:

leafArea.mSkipTokens = true;

将为当前节点创建的leafArea的mSkipTokens设置为true,那么后续在根据PendingArea数组生成DisplayArea层级结构的时候,就不会为这个PendingArea对象生成一个DisplayArea对象了。

一顿操作的最后结果相当于是,用TaskDisplayArea对象替换了为当前节点生成的Leaf。

2)、LEAF_TYPE_IME_CONTAINERS,和上面分析类似,不再为当前节点生成DisplayArea.Tokens,而是用之前保存在HierarchyBuilder.mImeContainer的ImeContainer。

那么为2.3.2生成的PendingArea数组添加Leaf后,PendingArea数组为:

areaForLayer[37] 初始 WindowedMagnification HideDisplayCutout OneHandedBackgroundPanel OneHanded FullscreenMagnification ImePlaceholder Leaf
areaForLayer[0] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHandedBackgroundPanel:0:0 OneHanded:0:0 FullscreenMagnification:0:0 Leaf:0:1
areaForLayer[1] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHandedBackgroundPanel:0:0 OneHanded:0:0 FullscreenMagnification:0:0 Leaf:0:1
areaForLayer[2] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0 DefaultTaskDisplayArea
areaForLayer[3] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0 Leaf:3:14
areaForLayer[4] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0 Leaf:3:14
areaForLayer[5] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0 Leaf:3:14
areaForLayer[6] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0 Leaf:3:14
areaForLayer[7] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0 Leaf:3:14
areaForLayer[8] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0 Leaf:3:14
areaForLayer[9] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0 Leaf:3:14
areaForLayer[10] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0 Leaf:3:14
areaForLayer[11] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0 Leaf:3:14
areaForLayer[12] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0 Leaf:3:14
areaForLayer[13] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0 Leaf:3:14
areaForLayer[14] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 FullscreenMagnification:2:0 Leaf:3:14
areaForLayer[15] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 ImePlaceholder:15:0 ImeContainer
areaForLayer[16] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:0:0 OneHanded:2:0 ImePlaceholder:15:0 ImeContainer
areaForLayer[17] Root:0:0 WindowedMagnification:0:0 OneHanded:17:0 FullscreenMagnification:17:0 Leaf:17:17
areaForLayer[18] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:18:0 OneHanded:18:0 FullscreenMagnification:18:0 Leaf:18:18
areaForLayer[19] Root:0:0 WindowedMagnification:0:0 OneHanded:19:0 FullscreenMagnification:19:0 Leaf:19:19
areaForLayer[20] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:20:0 OneHanded:20:0 FullscreenMagnification:20:0 Leaf:20:23
areaForLayer[21] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:20:0 OneHanded:20:0 FullscreenMagnification:20:0 Leaf:20:23
areaForLayer[22] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:20:0 OneHanded:20:0 FullscreenMagnification:20:0 Leaf:20:23
areaForLayer[23] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:20:0 OneHanded:20:0 FullscreenMagnification:20:0 Leaf:20:23
areaForLayer[24] Root:0:0 WindowedMagnification:0:0 Leaf:24:25
areaForLayer[25] Root:0:0 WindowedMagnification:0:0 Leaf:24:25
areaForLayer[26] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0 OneHanded:26:0 FullscreenMagnification:26:0 Leaf:26:27
areaForLayer[27] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0 OneHanded:26:0 FullscreenMagnification:26:0 Leaf:26:27
areaForLayer[28] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0 OneHanded:26:0 Leaf:28:28
areaForLayer[29] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0 OneHanded:26:0 FullscreenMagnification:29:0 Leaf:29:31
areaForLayer[30] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0 OneHanded:26:0 FullscreenMagnification:29:0 Leaf:29:31
areaForLayer[31] Root:0:0 WindowedMagnification:0:0 HideDisplayCutout:26:0 OneHanded:26:0 FullscreenMagnification:29:0 Leaf:29:31
areaForLayer[32] Root:0:0 HideDisplayCutout:32:0 OneHanded:32:0 Leaf:32:32
areaForLayer[33] Root:0:0 HideDisplayCutout:32:0 OneHanded:32:0 FullscreenMagnification:33:0 Leaf:33:35
areaForLayer[34] Root:0:0 HideDisplayCutout:32:0 OneHanded:32:0 FullscreenMagnification:33:0 Leaf:33:35
areaForLayer[35] Root:0:0 HideDisplayCutout:32:0 OneHanded:32:0 FullscreenMagnification:33:0 Leaf:33:35
areaForLayer[36] Root:0:0 Leaf:36:36

转换为树状图:

image

2.3.4 计算MaxLayer

2.2.3只设置了叶节点的mMaxLayer,这部分计算父节点的mMaxLayer。

root.computeMaxLayer();

调用PendingArea.computeMaxLayer方法去计算PendingArea.mMaxLayer的值:

        int computeMaxLayer() {
            for (int i = 0; i < mChildren.size(); i++) {
                mMaxLayer = Math.max(mMaxLayer, mChildren.get(i).computeMaxLayer());
            }
            return mMaxLayer;
        }

以当前节点为起点,向下查找最大的那个节点mMaxLayer作为当前节点的mMaxLayer。

最终的PendingArea数组为:

areaForLayer[37] 初始 WindowedMagnification HideDisplayCutout OneHandedBackgroundPanel OneHanded FullscreenMagnification ImePlaceholder Leaf
areaForLayer[0] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHandedBackgroundPanel:0:1 OneHanded:0:1 FullscreenMagnification:0:1 Leaf:0:1
areaForLayer[1] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHandedBackgroundPanel:0:1 OneHanded:0:1 FullscreenMagnification:0:1 Leaf:0:1
areaForLayer[2] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHanded:2:16 FullscreenMagnification:2:14 DefaultTaskDisplayArea
areaForLayer[3] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHanded:2:16 FullscreenMagnification:2:14 Leaf:3:14
areaForLayer[4] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHanded:2:16 FullscreenMagnification:2:14 Leaf:3:14
areaForLayer[5] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHanded:2:16 FullscreenMagnification:2:14 Leaf:3:14
areaForLayer[6] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHanded:2:16 FullscreenMagnification:2:14 Leaf:3:14
areaForLayer[7] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHanded:2:16 FullscreenMagnification:2:14 Leaf:3:14
areaForLayer[8] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHanded:2:16 FullscreenMagnification:2:14 Leaf:3:14
areaForLayer[9] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHanded:2:16 FullscreenMagnification:2:14 Leaf:3:14
areaForLayer[10] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHanded:2:16 FullscreenMagnification:2:14 Leaf:3:14
areaForLayer[11] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHanded:2:16 FullscreenMagnification:2:14 Leaf:3:14
areaForLayer[12] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHanded:2:16 FullscreenMagnification:2:14 Leaf:3:14
areaForLayer[13] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHanded:2:16 FullscreenMagnification:2:14 Leaf:3:14
areaForLayer[14] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHanded:2:16 FullscreenMagnification:2:14 Leaf:3:14
areaForLayer[15] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHanded:2:16 ImePlaceholder:15:16 ImeContainer
areaForLayer[16] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:0:16 OneHanded:2:16 ImePlaceholder:15:16 ImeContainer
areaForLayer[17] Root:0:0 WindowedMagnification:0:31 OneHanded:17:17 FullscreenMagnification:17:17 Leaf:17:17
areaForLayer[18] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:18:18 OneHanded:18:18 FullscreenMagnification:18:18 Leaf:18:18
areaForLayer[19] Root:0:0 WindowedMagnification:0:31 OneHanded:19:19 FullscreenMagnification:19:19 Leaf:19:19
areaForLayer[20] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:20:23 OneHanded:20:23 FullscreenMagnification:20:23 Leaf:20:23
areaForLayer[21] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:20:23 OneHanded:20:23 FullscreenMagnification:20:23 Leaf:20:23
areaForLayer[22] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:20:23 OneHanded:20:23 FullscreenMagnification:20:23 Leaf:20:23
areaForLayer[23] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:20:23 OneHanded:20:23 FullscreenMagnification:20:23 Leaf:20:23
areaForLayer[24] Root:0:0 WindowedMagnification:0:31 Leaf:24:25
areaForLayer[25] Root:0:0 WindowedMagnification:0:31 Leaf:24:25
areaForLayer[26] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:26:31 OneHanded:26:31 FullscreenMagnification:26:27 Leaf:26:27
areaForLayer[27] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:26:31 OneHanded:26:31 FullscreenMagnification:26:27 Leaf:26:27
areaForLayer[28] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:26:31 OneHanded:26:31 Leaf:28:28
areaForLayer[29] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:26:31 OneHanded:26:31 FullscreenMagnification:29:31 Leaf:29:31
areaForLayer[30] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:26:31 OneHanded:26:31 FullscreenMagnification:29:31 Leaf:29:31
areaForLayer[31] Root:0:0 WindowedMagnification:0:31 HideDisplayCutout:26:31 OneHanded:26:31 FullscreenMagnification:29:31 Leaf:29:31
areaForLayer[32] Root:0:0 HideDisplayCutout:32:35 OneHanded:32:35 Leaf:32:32
areaForLayer[33] Root:0:0 HideDisplayCutout:32:35 OneHanded:32:35 FullscreenMagnification:33:35 Leaf:33:35
areaForLayer[34] Root:0:0 HideDisplayCutout:32:35 OneHanded:32:35 FullscreenMagnification:33:35 Leaf:33:35
areaForLayer[35] Root:0:0 HideDisplayCutout:32:35 OneHanded:32:35 FullscreenMagnification:33:35 Leaf:33:35
areaForLayer[36] Root:0:0 Leaf:36:36

转换为树状图:

image

2.3.5 生成DisplayArea层级结构

            // We built a tree of PendingAreas above with all the necessary info to represent the
            // hierarchy, now create and attach real DisplayAreas to the root.
            root.instantiateChildren(mRoot, displayAreaForLayer, 0, featureAreas);

调用DisplayAreaPolicyBuilder.PendingArea.instantiateChildren方法生成DisplayArea层级结构。

        void instantiateChildren(DisplayArea<DisplayArea> parent, DisplayArea.Tokens[] areaForLayer,
                int level, Map<Feature, List<DisplayArea<WindowContainer>>> areas) {
            mChildren.sort(Comparator.comparingInt(pendingArea -> pendingArea.mMinLayer));
            for (int i = 0; i < mChildren.size(); i++) {
                final PendingArea child = mChildren.get(i);
                final DisplayArea area = child.createArea(parent, areaForLayer);
                if (area == null) {
                    // TaskDisplayArea and ImeContainer can be set at different hierarchy, so it can
                    // be null.
                    continue;
                }
                parent.addChild(area, WindowContainer.POSITION_TOP);
                if (child.mFeature != null) {
                    areas.get(child.mFeature).add(area);
                }
                child.instantiateChildren(area, areaForLayer, level + 1, areas);
            }
        }

当前root是上面的生成的PendingArea层级结构的根节点,传入的parent则是一个DisplayContent对象,那么这里按照root的mChildren的层级结构,以parent为根节点,生成一个DisplayArea层级结构。

重点看一下这里创建DisplayArea的DisplayAreaPolicyBuilder.PendingArea.createArea方法:

        private DisplayArea createArea(DisplayArea<DisplayArea> parent,
                DisplayArea.Tokens[] areaForLayer) {
            if (mExisting != null) {
                if (mExisting.asTokens() != null) {
                    // Store the WindowToken container for layers
                    fillAreaForLayers(mExisting.asTokens(), areaForLayer);
                }
                return mExisting;
            }
            if (mSkipTokens) {
                return null;
            }
            DisplayArea.Type type;
            if (mMinLayer > APPLICATION_LAYER) {
                type = DisplayArea.Type.ABOVE_TASKS;
            } else if (mMaxLayer < APPLICATION_LAYER) {
                type = DisplayArea.Type.BELOW_TASKS;
            } else {
                type = DisplayArea.Type.ANY;
            }
            if (mFeature == null) {
                final DisplayArea.Tokens leaf = new DisplayArea.Tokens(parent.mWmService, type,
                        "Leaf:" + mMinLayer + ":" + mMaxLayer);
                fillAreaForLayers(leaf, areaForLayer);
                return leaf;
            } else {
                return mFeature.mNewDisplayAreaSupplier.create(parent.mWmService, type,
                        mFeature.mName + ":" + mMinLayer + ":" + mMaxLayer, mFeature.mId);
            }
        }

1)、当mExisting不为null,即2.3.3中分析的TaskDisplayArea和ImeContainer的情况,此时不需要再创建DisplayArea对象,直接用mExisting。

2)、mSkipTokens为true,直接return,mSkipTokens是和mExisting是同一个逻辑下设置的。

3)、这里根据mMinLayer和mMaxLayer的值,将DisplayArea分为三种:

  • mMaxLayer小于APPLICATION_LAYER,即2,这类DisplayArea类型为ABOVE_TASKS。
  • mMinLayer大于APPLICATION_LAYER,这类DisplayArea类型为BELOW_TASKS。
  • 剩余情况下的DisplayArea类型为ANY。

4)、mFeature为null,那么创建一个DisplayArea.Tokens对象,这种情况对应2.3.3节分析的添加Leaf节点。

5)、如果mFeature不为null,那么创建一个DisplayArea对象。

那么最终生成的DisplayArea层级结构为:

DisplayContent
		#2 Leaf:36:36
		#1 HideDisplayCutout:32:35
			#0 OneHanded:32:35
				#1 FullscreenMagnification:33:35
					#0 Leaf:33:35
				# 0Leaf:32:32
		#0 WindowedMagnification:0:31
			#6 HideDisplayCutout:26:31
				#0 OneHanded:26:31
					#2 FullscreenMagnification:29:31
						#0 Leaf:29:31
					#1 Leaf:28:28
					#0 FullscreenMagnification:26:27
						#0 Leaf:26:27
			#5 Leaf:24:25
			#4 HideDisplayCutout:20:23
				#0 OneHanded:20:23
					#0 FullscreenMagnification:20:23
						#0 Leaf:20:23
			#3 OneHanded:19:19
				#0 FullscreenMagnification:19:19
					#0 Leaf:19:19
			#2 HideDisplayCutout:18:18
				#0 OneHanded:18:18
					#0 FullscreenMagnification:18:18
						#0 Leaf:18:18
			#1 OneHanded:17:17
				#0 FullscreenMagnification:17:17
					#0 Leaf:17:17
			#0 HideDisplayCutout:0:16
				#1 OneHanded:2:16
					#1 ImePlaceholder:15:16
						#0 ImeContainer
					#0 FullscreenMagnification:2:14
						#1 Leaf:3:14
						#0 DefaultTaskisplayArea
				#0 OneHandedBackgroundPanel:0:1
					#0 OneHanded:0:1
						#0 FullscreenMagnification:0:1
							#0 Leaf:0:1

对比adb shell dumpsys activity containers:

ROOT type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
  #0 Display 0 name="Built-in Screen" type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][1440,2960] bounds=[0,0][1440,2960]
   #2 Leaf:36:36 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
   #1 HideDisplayCutout:32:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
    #0 OneHanded:32:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
     #1 FullscreenMagnification:33:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
      #0 Leaf:33:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
     #0 Leaf:32:32 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
   #0 WindowedMagnification:0:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
    #6 HideDisplayCutout:26:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
     #0 OneHanded:26:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
      #2 FullscreenMagnification:29:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
       #0 Leaf:29:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
      #1 Leaf:28:28 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
      #0 FullscreenMagnification:26:27 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
       #0 Leaf:26:27 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
    #5 Leaf:24:25 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
    #4 HideDisplayCutout:20:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
     #0 OneHanded:20:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
      #0 FullscreenMagnification:20:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
       #0 Leaf:20:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
    #3 OneHanded:19:19 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
     #0 FullscreenMagnification:19:19 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
      #0 Leaf:19:19 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
    #2 HideDisplayCutout:18:18 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
     #0 OneHanded:18:18 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
      #0 FullscreenMagnification:18:18 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
       #0 Leaf:18:18 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
    #1 OneHanded:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
     #0 FullscreenMagnification:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
      #0 Leaf:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
    #0 HideDisplayCutout:0:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
     #1 OneHanded:2:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
      #1 ImePlaceholder:15:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
       #0 ImeContainer type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
      #0 FullscreenMagnification:2:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
       #1 Leaf:3:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
       #0 DefaultTaskDisplayArea type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
     #0 OneHandedBackgroundPanel:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
      #0 OneHanded:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
       #0 FullscreenMagnification:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
        #0 Leaf:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]

是一致的。

2.3.6 保存Leaf数组

            // Notify the root that we have finished attaching all the DisplayAreas. Cache all the
            // feature related collections there for fast access.
            mRoot.onHierarchyBuilt(mFeatures, displayAreaForLayer, featureAreas);

回调RootDisplayArea.onHierarchyBuilt:

    /** Callback after {@link DisplayArea} hierarchy has been built. */
    void onHierarchyBuilt(ArrayList<Feature> features, DisplayArea.Tokens[] areaForLayer,
            Map<Feature, List<DisplayArea<WindowContainer>>> featureToDisplayAreas) {
        if (mHasBuiltHierarchy) {
            throw new IllegalStateException("Root should only build the hierarchy once");
        }
        mHasBuiltHierarchy = true;
        mFeatures = Collections.unmodifiableList(features);
        mAreaForLayer = areaForLayer;
        mFeatureToDisplayAreas = featureToDisplayAreas;
    }

重点看一下第二个参数areaForLayer,是DisplayArea.Tokens[]类型的数组,看一下它的数据是如何得到的。

经过分析看到是在2.3.5,创建DisplayArea.Tokens的时候向areaForLayer里填充数据的:

            if (mFeature == null) {
                final DisplayArea.Tokens leaf = new DisplayArea.Tokens(parent.mWmService, type,
                        "Leaf:" + mMinLayer + ":" + mMaxLayer);
                fillAreaForLayers(leaf, areaForLayer);
                return leaf;
            }

再看一下fillAreaForLayers方法:

        private void fillAreaForLayers(DisplayArea.Tokens leaf, DisplayArea.Tokens[] areaForLayer) {
            for (int i = mMinLayer; i <= mMaxLayer; i++) {
                areaForLayer[i] = leaf;
            }
        }

也很简单,areaForLayer数组包含了每一个层级值对应的那个Leaf,即一个DisplayArea.Tokens对象。

3 向DisplayArea层级结构添加窗口

根据之前的分析,我们知道了:

  • 每种窗口类型,都可以通过WindowManagerPolicy.getWindowLayerFromTypeLw方法,返回一个相应的层级值。

  • DisplayArea层级结构中的每一个DisplayArea,都包含着一个层级值范围,这个层级值范围表明了这个DisplayArea可以容纳哪些类型的窗口。

那么我们可以合理进行推断添加窗口的一般流程:

WMS启动的时候添加DisplayContent的时候,首先是以该DisplayContent为根节点,创建了一个完整的DisplayArea层级结构。后续每次添加窗口的时候,都根据该窗口的类型,在DisplayArea层级结构中为该窗口寻找一个合适的父节点,然后将这个窗口添加到该父节点之下。

另外根据上面的分析还可以知道,在DisplayArea层级结构中,可以直接容纳窗口的父节点,有三种类型:

  • 容纳App窗口的TaskDisplayArea

  • 容纳输入法窗口的ImeContainer

  • 容纳其他非App类型窗口的DisplayArea.Tokens

这里我们分析一般流程,看下非App类型的窗口,如StatusBar、NavigationBar等窗口,是如何添加到DisplayArea中的。

注意,我们说的每一个窗口,指的是WindowState。但是DisplayArea.Tokens的定义是:

    /**
     * DisplayArea that contains WindowTokens, and orders them according to their type.
     */
    public static class Tokens extends DisplayArea<WindowToken> {

DisplayArea.Tokens是WindowToken的容器,因此DisplayArea.Tokens无法直接添加WindowState。

WindowToken则是WindowState的容器,每次新WindowState创建的时候,都会为这个WindowState创建一个WindowToken对象,然后将这个新创建的WindowState放入其中。

因此我们实际分析的,是WindowToken如何添加到DisplayArea层级结构中的。

最后需要修正一下说法,因为WindowToken不再是一个DisplayArea,而是一个WindowContainer。我们之前分析的DisplayArea层级结构,其中每一个节点都是一个DisplayArea,但是现在随着WindowToken的加入,DisplayArea层级结构这个说法需要转化为更通用的结构,也就是WindowContainer层级结构。

3.1 WindowManagerService.addWindow

    public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
            int displayId, int requestUserId, InsetsState requestedVisibility,
            InputChannel outInputChannel, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls) {

        // ......

        synchronized (mGlobalLock) {

            // ......

            WindowToken token = displayContent.getWindowToken(
                    hasParent ? parentWindow.mAttrs.token : attrs.token);

            // ......

            if (token == null) {

                // ......

                if (hasParent) {

                    // ......

                } else {
                    final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
                    token = new WindowToken.Builder(this, binder, type)
                            .setDisplayContent(displayContent)
                            .setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
                            .setRoundedCornerOverlay(isRoundedCornerOverlay)
                            .build();
                }
            }

            // ......

        }

        // ......

    }

调用WindowToken.Builder.build创建一个WindowToken对象。

3.2 WindowToken.Builder.build

        WindowToken build() {
            return new WindowToken(mService, mToken, mType, mPersistOnEmpty, mDisplayContent,
                    mOwnerCanManageAppTokens, mRoundedCornerOverlay, mFromClientToken, mOptions);
        }

3.3 WindowToken.init

    protected WindowToken(WindowManagerService service, IBinder _token, int type,
            boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens,
            boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) {
        super(service);
        token = _token;
        windowType = type;
        mOptions = options;
        mPersistOnEmpty = persistOnEmpty;
        mOwnerCanManageAppTokens = ownerCanManageAppTokens;
        mRoundedCornerOverlay = roundedCornerOverlay;
        mFromClientToken = fromClientToken;
        if (dc != null) {
            dc.addWindowToken(token, this);
        }
    }

在WindowToken构造方法中,调用DisplayContent.addWindowToken将WindowToken添加到以DisplayContent为根节点的WindowContainer层级结构中。

3.4 DisplayContent.addWindowToken

    void addWindowToken(IBinder binder, WindowToken token) {
        final DisplayContent dc = mWmService.mRoot.getWindowTokenDisplay(token);
        // ......

        mTokenMap.put(binder, token);

        if (token.asActivityRecord() == null) {
            // Set displayContent for non-app token to prevent same token will add twice after
            // onDisplayChanged.
            // TODO: Check if it's fine that super.onDisplayChanged of WindowToken
            //  (WindowsContainer#onDisplayChanged) may skipped when token.mDisplayContent assigned.
            token.mDisplayContent = this;
            // Add non-app token to container hierarchy on the display. App tokens are added through
            // the parent container managing them (e.g. Tasks).
            final DisplayArea.Tokens da = findAreaForToken(token).asTokens();
            da.addChild(token);
        }
    }

窗口可以分为App窗口和非App窗口。对于App窗口,则是由更细致的WindowToken的子类,ActivityRecord来存放。这里我们分析非App窗口的流程。

分两步走:

1)、调用DisplayContent.findAreaForToken为当前WindowToken寻找一个合适的父容器,DisplayArea.Tokens对象。

2)、将WindowToken添加到父容器中。

3.5 DisplayContent.findAreaForToken

    /**
     * Finds the {@link DisplayArea} for the {@link WindowToken} to attach to.
     * <p>
     * Note that the differences between this API and
     * {@link RootDisplayArea#findAreaForTokenInLayer(WindowToken)} is that this API finds a
     * {@link DisplayArea} in {@link DisplayContent} level, which may find a {@link DisplayArea}
     * from multiple {@link RootDisplayArea RootDisplayAreas} under this {@link DisplayContent}'s
     * hierarchy, while {@link RootDisplayArea#findAreaForTokenInLayer(WindowToken)} finds a
     * {@link DisplayArea.Tokens} from a {@link DisplayArea.Tokens} list mapped to window layers.
     * </p>
     *
     * @see DisplayContent#findAreaForTokenInLayer(WindowToken)
     */
    DisplayArea findAreaForToken(WindowToken windowToken) {
        return findAreaForWindowType(windowToken.getWindowType(), windowToken.mOptions,
                windowToken.mOwnerCanManageAppTokens, windowToken.mRoundedCornerOverlay);
    }

为传入的WindowToken找到一个DisplayArea对象来添加进去。

3.6 DisplayContent.findAreaForWindowType

    DisplayArea findAreaForWindowType(int windowType, Bundle options,
            boolean ownerCanManageAppToken, boolean roundedCornerOverlay) {
        // TODO(b/159767464): figure out how to find an appropriate TDA.
        if (windowType >= FIRST_APPLICATION_WINDOW && windowType <= LAST_APPLICATION_WINDOW) {
            return getDefaultTaskDisplayArea();
        }

        // Return IME container here because it could be in one of sub RootDisplayAreas depending on
        // the focused edit text. Also, the RootDisplayArea choosing strategy is implemented by
        // the server side, but not mSelectRootForWindowFunc customized by OEM.
        if (windowType == TYPE_INPUT_METHOD || windowType == TYPE_INPUT_METHOD_DIALOG) {
            return getImeContainer();
        }
        return mDisplayAreaPolicy.findAreaForWindowType(windowType, options,
                ownerCanManageAppToken, roundedCornerOverlay);
    }

  • 如果是App窗口,那么返回默认的TaskDisplayArea对象。

  • 如果是输入法窗口,那么返回ImeContainer。

  • 如果是其他类型,继续寻找。

和我们之前分析的逻辑一致。

3.7 DisplayAreaPolicyBuilder.Result.findAreaForWindowType

        @Override
        public DisplayArea.Tokens findAreaForWindowType(int type, Bundle options,
                boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
            return mSelectRootForWindowFunc.apply(type, options).findAreaForWindowTypeInLayer(type,
                    ownerCanManageAppTokens, roundedCornerOverlay);
        }

3.8 RootDisplayArea.findAreaForWindowTypeInLayer

    /** @see #findAreaForTokenInLayer(WindowToken)  */
    @Nullable
    DisplayArea.Tokens findAreaForWindowTypeInLayer(int windowType, boolean ownerCanManageAppTokens,
            boolean roundedCornerOverlay) {
        int windowLayerFromType = mWmService.mPolicy.getWindowLayerFromTypeLw(windowType,
                ownerCanManageAppTokens, roundedCornerOverlay);
        if (windowLayerFromType == APPLICATION_LAYER) {
            throw new IllegalArgumentException(
                    "There shouldn't be WindowToken on APPLICATION_LAYER");
        }
        return mAreaForLayer[windowLayerFromType];
    }

计算出该窗口的类型对应的层级值windowLayerFromType,然后从mAreaForLayer数组中,找到windowLayerFromType对应的那个DisplayArea.Tokens对象。

mAreaForLayer成员变量,定义为:

    /** Mapping from window layer to {@link DisplayArea.Tokens} that holds windows on that layer. */
    private DisplayArea.Tokens[] mAreaForLayer;

它里面的数据是在2.3.6节中填充,保存的是层级值到对应DisplayArea.Tokens对象的一个映射。

那么只要传入窗口类型,就可以通过WindowManagerPolicy.getWindowLayerFromTypeLw得到该窗口类型对应的层级值,然后根据该层级值从mAreaForLayer拿到容纳当前WindowToken的父容器,一个DisplayArea.Tokens对象。

3.9 DisplayArea.Tokens.addChild

        void addChild(WindowToken token) {
            addChild(token, mWindowComparator);
        }

这里调用了WindowContainer.addChild:

    /**
     * Adds the input window container has a child of this container in order based on the input
     * comparator.
     * @param child The window container to add as a child of this window container.
     * @param comparator Comparator to use in determining the position the child should be added to.
     *                   If null, the child will be added to the top.
     */
    @CallSuper
    protected void addChild(E child, Comparator<E> comparator) {
        if (!child.mReparenting && child.getParent() != null) {
            throw new IllegalArgumentException("addChild: container=" + child.getName()
                    + " is already a child of container=" + child.getParent().getName()
                    + " can't add to container=" + getName());
        }

        int positionToAdd = -1;
        if (comparator != null) {
            final int count = mChildren.size();
            for (int i = 0; i < count; i++) {
                if (comparator.compare(child, mChildren.get(i)) < 0) {
                    positionToAdd = i;
                    break;
                }
            }
        }

        if (positionToAdd == -1) {
            mChildren.add(child);
        } else {
            mChildren.add(positionToAdd, child);
        }

        // Set the parent after we've actually added a child in case a subclass depends on this.
        child.setParent(this);
    }

传入了一个Comparator:

        private final Comparator<WindowToken> mWindowComparator =
                Comparator.comparingInt(WindowToken::getWindowLayerFromType);

很明显,在将WindowToken添加到父容器的时候,将新添加的WindowToken的层级值和父容器中的其他WindowToken的层级值进行比较,保证新添加的WindowToken在父容器中能够按照层级值的大小插入到合适的位置。

4 总结

4.1 DisplayArea类型

4.1.1 根据类的继承关系分类

一种是从DisplayArea类的继承关系出发,有以下关系:

image

4.1.2 根据DisplayArea.Type类的定义分类

根据DisplayArea.Type类的定义:

    enum Type {
        /** Can only contain WindowTokens above the APPLICATION_LAYER. */
        ABOVE_TASKS,
        /** Can only contain WindowTokens below the APPLICATION_LAYER. */
        BELOW_TASKS,
        /** Can contain anything. */
        ANY;

        // ......
    }

可以将DisplayArea分为三类,分类的依据当前DisplayArea和APPLICATION_LAYER的关系:

            if (mMinLayer > APPLICATION_LAYER) {
                type = DisplayArea.Type.ABOVE_TASKS;
            } else if (mMaxLayer < APPLICATION_LAYER) {
                type = DisplayArea.Type.BELOW_TASKS;
            } else {
                type = DisplayArea.Type.ANY;
            }

这种分类,首先把窗口划分为了App窗口和非App窗口。

其次,对于非App窗口,再根据其层级与App窗口层级的高低关系,分为位于App窗口之上的非App窗口(即ABOVE_TASKS),和位于App窗口之下的非App窗口(即BELOW_TASKS)。

4.1.3 根据Feature分类

在上面分析DisplayArea层级结构的创建流程中,我们在DisplayAreaPolicy.DefaultProvider.configureTrustedHierarchyBuilder方法中看到了6种Feature的添加:

        private void configureTrustedHierarchyBuilder(HierarchyBuilder rootHierarchy,
                WindowManagerService wmService, DisplayContent content) {
            // WindowedMagnification should be on the top so that there is only one surface
            // to be magnified.
            rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",
                    FEATURE_WINDOWED_MAGNIFICATION)
                    .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                    .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                    // Make the DA dimmable so that the magnify window also mirrors the dim layer.
                    .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
                    .build());
            if (content.isDefaultDisplay) {
                // Only default display can have cutout.
                // See LocalDisplayAdapter.LocalDisplayDevice#getDisplayDeviceInfoLocked.
                rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "HideDisplayCutout",
                        FEATURE_HIDE_DISPLAY_CUTOUT)
                        .all()
                        .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL, TYPE_STATUS_BAR,
                                TYPE_NOTIFICATION_SHADE)
                        .build())
                        .addFeature(new Feature.Builder(wmService.mPolicy,
                                "OneHandedBackgroundPanel",
                                FEATURE_ONE_HANDED_BACKGROUND_PANEL)
                                .upTo(TYPE_WALLPAPER)
                                .build())
                        .addFeature(new Feature.Builder(wmService.mPolicy, "OneHanded",
                                FEATURE_ONE_HANDED)
                                .all()
                                .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)
                                .build());
            }
            rootHierarchy
                    .addFeature(new Feature.Builder(wmService.mPolicy, "FullscreenMagnification",
                            FEATURE_FULLSCREEN_MAGNIFICATION)
                            .all()
                            .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, TYPE_INPUT_METHOD,
                                    TYPE_INPUT_METHOD_DIALOG, TYPE_MAGNIFICATION_OVERLAY,
                                    TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)
                            .build())
                    .addFeature(new Feature.Builder(wmService.mPolicy, "ImePlaceholder",
                            FEATURE_IME_PLACEHOLDER)
                            .and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
                            .build());
        }
    }

这些Feature都对应一个特定的的DisplayArea。

但是再看DisplayArea的层级结构图:

image

还有一些节点的对应Feature却没有看到,即根节点DisplayContent,叶节点TaskDisplayArea和叶节点Leaf对应的DisplayArea.Tokens。

但是每次创建DisplayArea的时候都会传入一个对应的FeatureId的,之前分析的时候可能没有注意:

1)、DisplayContent:

    DisplayContent(Display display, RootWindowContainer root) {
        super(root.mWindowManager, "DisplayContent", FEATURE_ROOT);
        // ......
    }

2)、TaskDisplayArea:

            final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService,
                    "DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);

3)、DisplayArea.Tokens:

        Tokens(WindowManagerService wms, Type type, String name) {
            super(wms, type, name, FEATURE_WINDOW_TOKENS);
        }

这样,所有的FeatureID,都已经找到了使用的地方了:

   /**
     * The value in display area indicating that no value has been set.
     */
    public static final int FEATURE_UNDEFINED = -1;

    /**
     * The Root display area on a display
     */
    public static final int FEATURE_SYSTEM_FIRST = 0;

    /**
     * The Root display area on a display
     */
    public static final int FEATURE_ROOT = FEATURE_SYSTEM_FIRST;

    /**
     * Display area hosting the default task container.
     */
    public static final int FEATURE_DEFAULT_TASK_CONTAINER = FEATURE_SYSTEM_FIRST + 1;

    /**
     * Display area hosting non-activity window tokens.
     */
    public static final int FEATURE_WINDOW_TOKENS = FEATURE_SYSTEM_FIRST + 2;

    /**
     * Display area for one handed feature
     */
    public static final int FEATURE_ONE_HANDED = FEATURE_SYSTEM_FIRST + 3;

    /**
     * Display area that can be magnified in
     * {@link Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW}. It contains all windows
     * below {@link WindowManager.LayoutParams#TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY}.
     */
    public static final int FEATURE_WINDOWED_MAGNIFICATION = FEATURE_SYSTEM_FIRST + 4;

    /**
     * Display area that can be magnified in
     * {@link Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN}. This is different from
     * {@link #FEATURE_WINDOWED_MAGNIFICATION} that the whole display will be magnified.
     * @hide
     */
    public static final int FEATURE_FULLSCREEN_MAGNIFICATION = FEATURE_SYSTEM_FIRST + 5;

    /**
     * Display area for hiding display cutout feature
     * @hide
     */
    public static final int FEATURE_HIDE_DISPLAY_CUTOUT = FEATURE_SYSTEM_FIRST + 6;

    /**
     * Display area that the IME container can be placed in. Should be enabled on every root
     * hierarchy if IME container may be reparented to that hierarchy when the IME target changed.
     * @hide
     */
    public static final int FEATURE_IME_PLACEHOLDER = FEATURE_SYSTEM_FIRST + 7;

    /**
     * Display area for one handed background layer, which preventing when user
     * turning the Dark theme on, they can not clearly identify the screen has entered
     * one handed mode.
     * @hide
     */
    public static final int FEATURE_ONE_HANDED_BACKGROUND_PANEL = FEATURE_SYSTEM_FIRST + 8;

    /**
     * The last boundary of display area for system features
     */
    public static final int FEATURE_SYSTEM_LAST = 10_000;

看一下这些Feature的含义都是什么:

  • FEATURE_ROOT,一个屏幕上的根DisplayArea,对应DisplayContent。

  • FEATURE_DEFAULT_TASK_CONTAINER,容纳默认Task容器的DisplayArea,对应TaskDisplayArea。

  • FEATURE_WINDOW_TOKENS,容纳非activity窗口的DisplayArea,对应DisplayArea.Tokens。

  • FEATURE_ONE_HANDED,用于单手模式的DisplayArea,对应名为“OneHanded”的DisplayArea。

  • FEATURE_WINDOWED_MAGNIFICATION,在ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW模式下可以对窗口的某些区域进行放大的DisplayArea,对应名为“WindowedMagnification”的DisplayArea。

  • FEATURE_FULLSCREEN_MAGNIFICATION,在ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN模式下可以对整个屏幕进行放大的DisplayArea,对应名为“FullscreenMagnification”的DisplayArea。

  • FEATURE_HIDE_DISPLAY_CUTOUT,隐藏DisplayCutout的DisplayArea,对应名为“HideDisplayCutout”的DisplayArea。

  • FEATURE_IME_PLACEHOLDER,存放输入法窗口的DisplayArea,对应名为“ImePlaceholder”的DisplayArea。

  • FEATURE_ONE_HANDED_BACKGROUND_PANEL,容纳单手背景图层的DisplayArea,避免用户开启暗黑模式后,无法分辨屏幕是否已经进入了单手模式,对应名为“OneHandedBackgroundPanel”的DisplayArea。

4.2 DisplayArea层级结构生成规则

这里想要讨论一下为什么DisplayArea层级结构呈现为这样的形式:

image

在2.3节中分析了生成DisplayArea树的流程,但是感觉不够直观,这里借鉴了:

https://blog.csdn.net/shensky711/article/details/121530510

的分析方式,用颜色对各个DisplayArea进行标记。

分析前我们需要知道几点前提:

  • 属于同一层级值的窗口,统一由一个Leaf管理,这个Leaf可以是DisplayArea.Tokens,也可以是TaskDisplayArea或者ImeContainer,这里暂且认为一个Leaf代表的就是同一类型的窗口。
  • 为DisplayArea定义的各种Feature,代表了这个DisplayArea属下的窗口所具有的特征。Leaf虽然本身拥有的Feature,如FEATURE_WINDOW_TOKENS,没有对应的一个具体的功能,但是Leaf又是被层级结构中的父节点所管理的,所以它也会拥有父节点DisplayArea对应的Feature代表的特征。比如一个Leaf的父节点是WindowedMagnification,那么这个Leaf管理的所有窗口都具有窗口放大功能。
  • 另外虽然一个DisplayArea只有一个Feature,但是由于DisplayArea的互相嵌套,那么一个Leaf可能会处于多级DisplayArea之下,所以一个Leaf可能具备多个Feature,比如Leaf:33:35,它的父节点从下往上依次是FullscreenMagnification,OneHanded,HideDisplayCutout,那么这个Leaf下的所有窗口,都具备这些Feature带来的特征。

以此为基础,来分析一下DisplayArea层级结构的生成过程。

1)、由于定义的层级值是0~36,所以最初我们可能为每一个层级值都创建了一个Leaf对象。如果想要某一个Leaf拥有某一个Feature代表的特征,那么就为这个Leaf添加对应的父节点,那么最初的设计可能是这样的:

image

因为有37个Leaf,所以总共有37列。这里的每一个有颜色的格子都代表一个DisplayArea对象。空白格子说明该列的Leaf管理的窗口不希望有该Feature代表的功能,因此没有针对该Feature创建一个DisplayArea对象。

所以这里有37棵独立的DisplayArea树,每一个树的根节点都是一个DisplayContent对象,叶节点都是一个Leaf,然后中间节点则是有多有少,这取决于这棵树的leaf希望拥有哪些Feature。

2)、对于每一棵DisplayArea树,都是父节点连接子节点,中间不能有空白节点。但是上面的表格,我们能看到是有格子是空白的。我们这里是希望表格同样能够反映DisplayArea层级结构,所以我们需要去掉空白格子。

举个例子,看一下36列,该列下的Leaf不需要任何额外Feature,因此不需要再为该Leaf创建任何父DisplayArea,直接将该Leaf添加到DisplayContent的子节点数组中,在表格中就是将该Leaf对应的格子上移,直接移动到DisplayContent所代表的格子之下。

这也就意味着每一个有颜色的格子如果上方有空白格子,那么就将其上移,最终得到:

image

3)、现在每一棵树都是父节点连接子节点,且中间没有空白节点了,但是此时并不够成一个层级结构,而仍然是37棵独立的树,需要进一步优化。首先我们看到,每一个屏幕只对应一个DisplayContent对象,那么这37棵树,它们的根节点其实都是同一个DisplayContent。此外,对于表格中左右相邻的DisplayArea,如果它们的父DisplayArea是同类型的(拥有的Feature相同),那么这种情况下,就可以复用父DisplayArea,即没有必要创建多个DisplayArea,而是只创建一个父DisplayArea,然后将这些左右相邻的DisplayArea全部添加到该父DisplayArea的子节点数组之中,也能达到同样的效果,即这些DisplayArea都具有了父DisplayArea的Feature。此时,这些表格中左右相邻的DisplayArea,由同一个父节点管理,因此表格上看它们左右相邻,在实际的层级结构中,它们也是处于同一层级。

那么表格中如果一个相邻格子的颜色相同,就把这两个格子合并,即DisplayArea的复用。最终得到:

image

再对比之前的树状图:

image

也是符合的。

4.3 向DisplayArea层级结构添加窗口

根据DisplyArea树状图可知,对于0~36的每一个层级值,在DisplayArea层级结构中都有相应的Leaf对应。因此每次添加新窗口的时候,只需要将该窗口的窗口类型换算为相应的层级值,然后将该新窗口添加到该层级值对应的Leaf下即可。

层级值反映了一个Leaf在DisplayArea层级结构中的层级高低,层级值越大,该Leaf在DisplayArea层级结构中的层级也越高。而Leaf是窗口的容器,Leaf层级值越大,其管理的窗口在Z轴的顺序也就越高。这也说明了窗口类型值越大的窗口,其在Z轴上的顺序不一定越高,因为窗口类型值和层级值并不是一个正相关的关系。

标签:DisplayArea,12,Leaf,areaForLayer,Android,WindowedMagnification,Root,HideDisplayC
From: https://www.cnblogs.com/ukynho/p/16659898.html

相关文章

  • I [NOIP2012]开车旅行 每次往第一或者第二近的点走,求最大比值 倍增算法 set
    链接:https://ac.nowcoder.com/acm/problem/16562来源:牛客网题目描述小A和小B决定利用假期外出旅行,他们将想去的城市从1到N编号,且编号较......
  • Android.mk 文件编写
    Android.mk以下内容通常够用,如需添加其他变量,百度查看LOCAL_PATH:=$(callmy-dir)//源码所在目录,写法固定include$(CLEAR_VARS)//清除除外LOCAL_PATH变量以外的其......
  • android | adb找不到夜神模拟器 | 查看android手机cpu架构
    adb找不到夜神模拟器|查看android手机cpu架构找不到模拟器参考:https://www.jianshu.com/p/8af043534fc4先手动建立连接就行:然后查看手机的cpu架构:这条是android特有......
  • 干货 | APP自动化Android之属性获取与断言
    ⬇️点击“下方链接”,提升测试核心竞争力!>>更多技术文章分享和免费资料领取断言是UI自动化测试的三要素之一,是UI自动化不可或缺的部分。我们使用定位器定位到元素后,通......
  • 【做题笔记】CF1288C Two Arrays
    ProblemCF1288CTwoArrays题目大意:构造两个长度为\(m\),值域为\(n\)的序列\(a,b\),满足\(a\)单调不降,\(b\)单调不升,且\(\foralli\in[1,m],a_i\leb_i\),求合......
  • MathProblem 84 12 pearls and a scale problem
    Infrontofyouare12pearls,11beingrealandonefake.Therealonesallweighthesameandthefakeonediffersinweightfromtherealones(mayweighmo......
  • 【JS】112. 路径总和
    112.路径总和代码DFSvarhasPathSum=function(root,targetSum){//找到没有根了,那么就说明这条路行不通if(!root){returnfalse;}//......
  • Educational Codeforces Round 122 E
    E.SpanningTreeQueries纯暴力做法t了我们考虑如何优化我们可以发现要是所有绝对值曲线单调性不变我们MST的答案是可以O(1)转移的res+=(x-prex)*(num1-num2)单调性改变......
  • Flink1.12学习笔记
    一、Flink简介Flink是有状态的流式计算。Flink是一个框架和分布式处理引擎,用于在无边界和有边界数据流上进行有状态的计算。Flink可以部署在任意地方,Apacheflink是一......
  • SQL server 2012 安装教程
    server2012安装教程链接:https://pan.baidu.com/s/1TgS0FHB_Rc9mvpO89QiUtQ?pwd=gyiq提取码:gyiq--来自百度网盘超级会员V3的分享点击“setup.exe”点击左侧"安装",......