Android T 窗口层级其二 —— 层级结构树的构建(更新中)

如何通过dump中的内容找到对应的代码?
我们dump窗口层级发现会有很多信息,adb shell dumpsys activity containers
在这里插入图片描述这里我们以其中的DefaultTaskDisplayArea为例

在这里插入图片描述在源码的framework目录下查找该字符串,找到对应的代码就可以通过打印堆栈或者搜索代码跟踪的方式找到其调用逻辑

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

也就是这一句

当然我们上篇文章也讲到了DisplayContent代表的屏幕的DisplayArea层级结构的根节点,我们可以直接从DisplayContent.java的构造方法出发,追踪其流程

DisplayContent初始化

代码路径:/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

/**
     * 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) {
        super(root.mWindowManager, "DisplayContent", FEATURE_ROOT);
        ......
        final Transaction pendingTransaction = getPendingTransaction();
        configureSurfaces(pendingTransaction);
        pendingTransaction.apply();
        ......
    }

创建新的DisplayContent实例,将其自身添加到根窗口容器并初始化直接子级,这里我主要关注一下configureSurfaces(pendingTransaction);

 /**
     * Configures the surfaces hierarchy for DisplayContent
     * This method always recreates the main surface control but reparents the children
     * if they are already created.
     * @param transaction as part of which to perform the configuration
     */
    private void configureSurfaces(Transaction transaction) {
        final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(mSession)
                .setOpaque(true)
                .setContainerLayer()
                .setCallsite("DisplayContent");
        mSurfaceControl = b.setName(getName()).setContainerLayer().build();

        if (mDisplayAreaPolicy == null) {
            // Setup the policy and build the display area hierarchy.
            // Build the hierarchy only after creating the surface so it is reparented correctly
            mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(
                    mWmService, this /* content */, this /* root */,
                    mImeWindowsContainer);
        }
        ......
       
    }

通过DisplayContent来配置图层结构

DisplayAreaPolicy初始化

代码路径:/frameworks/base/services/core/java/com/android/server/wm/DisplayAreaPolicy.java

mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(
        mWmService, this /* content */, this /* root */,
        mImeWindowsContainer)

调用DisplayAreaPolicy中的Provider接口instantiate方法,去初始化一个DisplayArea层级结构
记住这边传递的参数,后面代码需要结合起来看

DisplayAreaPolicy.Provider

    /**
     * Provider for {@link DisplayAreaPolicy} instances.
     *
     * <p>By implementing this interface and overriding the
     * {@code config_deviceSpecificDisplayAreaPolicyProvider}, a device-specific implementations
     * of {@link DisplayAreaPolicy} can be supplied.
     */
    public interface Provider {
        /**
         * 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方法

DisplayAreaPolicy.DefaultProvider

 /** Provider for platform-default display area policy. */
    static final class DefaultProvider implements DisplayAreaPolicy.Provider {
        @Override
        public DisplayAreaPolicy instantiate(WindowManagerService wmService,
                DisplayContent content, RootDisplayArea root,
                DisplayArea.Tokens imeContainer) {
             //1.创建一个名为“DefaultTaskDisplayArea”的TaskDisplayArea,并将其添加到List中
            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.
            //2.创建HierarchyBuilder
            final HierarchyBuilder rootHierarchy = new HierarchyBuilder(root);
            // Set the essential containers (even if the display doesn't support IME).
            //3.1添加ImeContainer到HierarchyBuilder
            //3.2创建并保存默认TaskDisplayArea到HierarchyBuilder
            rootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList);
            if (content.isTrusted()) {
                // Only trusted display can have system decorations.
                //4.为HierarchyBuilder添加Feature
                configureTrustedHierarchyBuilder(rootHierarchy, wmService, content);
            }

            // Instantiate the policy with the hierarchy defined above. This will create and attach
            // all the necessary DisplayAreas to the root.
            //5.生成DisplayArea层级结构
            return new DisplayAreaPolicyBuilder().setRootHierarchy(rootHierarchy).build(wmService);
        }

这里DefaultProvider实现了这个接口。
这个方法主要干了这几件事情:

1.初始化TaskDisplayArea

final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService,
        "DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);
final List<TaskDisplayArea> tdaList = new ArrayList<>();
tdaList.add(defaultTaskDisplayArea);

创建一个名为“DefaultTaskDisplayArea”的TaskDisplayArea,并将其添加到List中

2.创建HierarchyBuilder

final HierarchyBuilder rootHierarchy = new HierarchyBuilder(root);

HierarchyBuilder是什么?是用来定义在整个逻辑显示的根里面所需的一些Feature
HierarchyBuilder是在DisplayAreaPolicyBuilder中定义的
代码路径:frameworks/base/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java

    /**
     *  Builder to define {@link Feature} and {@link DisplayArea} hierarchy under a
     * {@link RootDisplayArea}
     */
    static class HierarchyBuilder {
        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;

        private final RootDisplayArea mRoot;
        private final ArrayList<DisplayAreaPolicyBuilder.Feature> mFeatures = new ArrayList<>();
        private final ArrayList<TaskDisplayArea> mTaskDisplayAreas = new ArrayList<>();
        @Nullable
        private DisplayArea.Tokens mImeContainer;

        HierarchyBuilder(RootDisplayArea root) {
            mRoot = root;
        }
        ......
    }

从代码中我们可以看出,HierarchyBuilder用来构建一个DisplayArea层级结构,该层级结构的根节点
其构造方法HierarchyBuilder(RootDisplayArea root)传入的是RootDisplayArea的对象。
结合前面的configureSurfaces方法中我们可以发现传入的是DisplayContent,即HierarchyBuilder以DisplayContent对象为根节点,生成一个DisplayArea层级结构。

3.1添加ImeContainer到HierarchyBuilder

rootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList);

我们先看setImeContainer(imeContainer)部分。其中参数imeContainer是DisplayArea.Tokens的对象。

在DisplayContent中DisplayAreaPolicy初始化时,传递了一个mImeWindowsContainer对应我们这里的imeContainer形参,其是在DisplayContent中定义并初始化的
代码路径:/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

    // 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就是输入法的容器,其继承在DisplayContent中DisplayArea.Tokens

    /**
     * Container for IME windows.
     *
     * This has some special behaviors:
     * - layers assignment is ignored except if setNeedsLayer() has been called before (and no
     *   layer has been assigned since), to facilitate assigning the layer from the IME target, or
     *   fall back if there is no target.
     * - the container doesn't always participate in window traversal, according to
     *   {@link #skipImeWindowsDuringTraversal()}
     */
    private static class ImeContainer extends DisplayArea.Tokens {

HierarchyBuilder的setImeContainer方法
代码路径:frameworks/base/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java

        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层级结构时可以直接拿来使用。

3.2添加TaskDisplayArea到HierarchyBuilder

rootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList);

这里我们看setTaskDisplayAreas(tdaList)部分,第一步【1.初始化TaskDisplayArea】的时候,就已经把名为“DefaultTaskDisplayArea”的TaskDisplayArea,并将其添加到tdaList中,

		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。从dumpsys activity containers 中我们也可以看到,整个文件也只有一个“DefaultTaskDisplayArea”

4.为HierarchyBuilder添加Feature

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

configureTrustedHierarchyBuilder这个方法就在DisplayAreaPolicy.DefaultProvider内部

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, "OneHanded",
                                FEATURE_ONE_HANDED)
                                .all()
                                .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL,
                                        TYPE_SECURE_SYSTEM_OVERLAY)
                                .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:WindowedMagnification、HideDisplayCutout、OneHanded、FullscreenMagnification、ImePlaceholder,这些Feature其实也就是我们在dumpsys中看到那些,还有一些关键方法all()、and()、except()、upto()、build()等
在我们正式开始聊这个几个Feature添加之前,我们先来看看,Feature是怎么定义的

Feature的定义

从HierarchyBuilder的addFeature方法跟踪发现,Feature是在DisplayAreaPolicyBuilder中定义的

        HierarchyBuilder addFeature(DisplayAreaPolicyBuilder.Feature feature) {
            mFeatures.add(feature);
            return this;
        }

Feature的定义
代码路径/frameworks/base/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java

    /**
     * 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;

        private Feature(String name, int id, boolean[] windowLayers,
                NewDisplayAreaSupplier newDisplayAreaSupplier) {
            mName = name;
            mId = id;
            mWindowLayers = windowLayers;
            mNewDisplayAreaSupplier = newDisplayAreaSupplier;
        }
        ......
    }

首先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的特征
  • mWindowLayers:代表了这个DisplayArea可以包含哪些层级对应的窗口
  • mNewDisplayAreaSupplier:只是一个接口,内部定义一个create方法。

关键是其Feature内部定义Builder类以及其build()方法

Feature.Builder和Feature.Builder.build()
static class Builder {
            private final WindowManagerPolicy mPolicy;
            private final String mName;
            private final int mId;
            private final boolean[] mLayers;
            private NewDisplayAreaSupplier mNewDisplayAreaSupplier = DisplayArea::new;
            private boolean mExcludeRoundedCorner = true;

            /**
             * 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];
            }
            ......
            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
其中mLayers = new boolean[mPolicy.getMaxWindowLayer() + 1]; mPolicy.getMaxWindowLayer()返回的是窗口最大层数。

    /**
     * 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;
    }

代码中最大层数是36,这里+1,则也就是mLayers = new boolean[37],即窗口层级区间为[0,36]
在看看build()方法中的 mLayers[mPolicy.getMaxWindowLayer()] = false;,则表示mLayers[36] = false,即第36层在build时会置为false(注:mExcludeRoundedCorner这个变量的值一直是true,没有改动)

下面我们来说说构建Feature的关键星魂

构建Feature的核心方法

以下代码均在DisplayAreaPolicyBuilder.Feature.Builder中

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

将mLayers数组中的所有元素都设置为true,表示当前DisplayArea可以包含所有类型的窗口。
简述,all()就是把所有类型窗口置为true(添加)

Feature第二星魂:and()
        /**
         * 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;
        }

先将传入的窗口类型先转换为对应的层级值,然后将mLayers数组中与该层级值对应的元素设置为true,表示该DisplayArea可以包含传入的窗口类型对应的窗口。
简述,and就是把你传入的所有参数(窗口类型)置为true(添加)

Feature第三星魂:except()
        /**
         * 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;
        }

先将传入的窗口类型先转换为对应的层级值,然后将mLayers数组中与该层级值对应的元素设置为false,表示该DisplayArea不再包含传入的窗口类型对应的窗口。
简述,except就是你传入的所有参数(窗口类型)置为false(不添加)

Feature第四星魂(必点):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;
        }

先将传入的窗口类型先转换为对应的层级值,然后将mLayers数组中与该层级值对应的的元素之前的所有元素(包含该元素)设置为true,表示当前DisplayArea可以包含比传入的窗口类型层级值低的所有窗口。
简述,upTo把就是[0,typeInclusive]区间内的所有类型窗口置为true(添加)。
其中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:
                return  4;
            case TYPE_INPUT_CONSUMER:
                return  5;
            case TYPE_SYSTEM_DIALOG:
                return  6;
            case TYPE_TOAST:
                // toasts and the plugged-in battery thing
                return  7;
            case TYPE_PRIORITY_PHONE:
                // SIM errors and unlock.  Not sure if this really should be in a high layer.
                return  8;
            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 ? 12 : 9;
            case TYPE_APPLICATION_OVERLAY:
                return  11;
            case TYPE_INPUT_METHOD:
                // on-screen keyboards and other such input method user interfaces go here.
                return  13;
            case TYPE_INPUT_METHOD_DIALOG:
                // on-screen keyboards and other such input method user interfaces go here.
                return  14;
            case TYPE_STATUS_BAR:
                return  15;
            case TYPE_STATUS_BAR_ADDITIONAL:
                return  16;
            case TYPE_NOTIFICATION_SHADE:
                return  17;
            case TYPE_STATUS_BAR_SUB_PANEL:
                return  18;
            case TYPE_KEYGUARD_DIALOG:
                return  19;
            case TYPE_VOICE_INTERACTION_STARTING:
                return  20;
            case TYPE_VOICE_INTERACTION:
                // voice interaction layer should show above the lock screen.
                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 : 10;
            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 : 9;
            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;
        }
    }

关于各窗口类型的解读可以参考链接: Android 窗口常见参数汇总

方法简述:
这个方法返回给定窗口类型对应的层级值,用于控制不同类型的窗口在屏幕上的显示层次。

  • type:要分配的窗口的类型。

  • canAddInternalSystemWindow:是否可以添加内部系统窗口。
    例如,假如我们有一个内部系统窗口,且我们的这个参数canAddInternalSystemWindow为true的情况下,则Alert Window窗口类型所分配的层级大于TYPE_APPLICATION_OVERLAY;为false则小于TYPE_APPLICATION_OVERLAY(可以对照代码验证看看)

  • roundedCornerOverlay:{#code true}表示所有者窗口是圆角覆盖。

  • 返回值: int一个任意整数,用于对窗口进行排序,较低的数字在高数字的下面。

其中APPLICATION_LAYER的值为2,即表示所有App窗口会被归类到这一个层级
而上述方法中的最后一句default中则表示所有没有分类的窗口层级为3
后面我们只需要查这个代码即可知道每个类型的返回值是多少

Feature的添加

WindowedMagnification
            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

3.upTo里面的参数是TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY(32),则代表[0,TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY]区间内全部添加

4.except里面参数是TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY(32),则除去该类型

最终我们可以得到WindowedMagnification的所包含的层级区间在[0,31]

HideDisplayCutout
                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())

1.设置Feature的mName为"HideDisplayCutout"。

2.设置Feature的mId为FEATURE_HIDE_DISPLAY_CUTOUT

3.all()把所有的窗口类型添加进来

4.except里面的类型踢掉TYPE_NAVIGATION_BAR(24),TYPE_NAVIGATION_BAR_PANEL(25),TYPE_STATUS_BAR(15),TYPE_NOTIFICATION_SHADE(17)

5.build()方法会把第36层(从0开始算)踢掉,前面讲该方法时说过

最终我们可以得到HideDisplayCutout所包含的层级为0-16,18,20-23,26-35

OneHanded
                        .addFeature(new Feature.Builder(wmService.mPolicy, "OneHanded",
                                FEATURE_ONE_HANDED)
                                .all()
                                .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL,
                                        TYPE_SECURE_SYSTEM_OVERLAY)
                                .build());

1.设置Feature的mName为"OneHanded"。

2.设置Feature的mId为FEATURE_ONE_HANDED

3.all()把所有的窗口类型添加进来

4.except里面的类型踢掉TYPE_NAVIGATION_BAR(24),TYPE_NAVIGATION_BAR_PANEL(25),TYPE_SECURE_SYSTEM_OVERLAY(33)

5.去掉第36层

最终我们可以得到OneHanded所包含的层级为0-23,26-34,35

FullscreenMagnification
            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())

1.设置Feature的mName为"FullscreenMagnification"。

2.设置Feature的mId为FEATURE_FULLSCREEN_MAGNIFICATION

3.all()把所有的窗口类型添加进来

4.except里面的类型踢掉TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY(32),TYPE_INPUT_METHOD(13),TYPE_INPUT_METHOD_DIALOGERLAY(14),TYPE_MAGNIFICATION_OVERLAY(28),TYPE_NAVIGATION_BAR(24),TYPE_NAVIGATION_BAR_PANEL(25)

5.去掉第36层

最终我们可以得到FullscreenMagnification所包含的层级为0-12,15-23,26-27,29-31,33-35

ImePlaceholder
                    .addFeature(new Feature.Builder(wmService.mPolicy, "ImePlaceholder",
                            FEATURE_IME_PLACEHOLDER)
                            .and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
                            .build());

1.设置Feature的mName为"ImePlaceholder"。

2.设置Feature的mId为FEATURE_IME_PLACEHOLDER

3.and()把TYPE_INPUT_METHOD(13),TYPE_INPUT_METHOD_DIALOGERLAY(14)窗口类型添加进来

最终我们可以得到ImePlaceholder所包含的层级为13-14

Feature层级表

根据上面的添加过程,我们整理为一张表

艺名真名影响窗口层级
WindowedMagnificationFEATURE_WINDOWED_MAGNIFICATION0-31
HideDisplayCutoutFEATURE_HIDE_DISPLAY_CUTOUT0-16,18,20-23,26-35
OneHandedFEATURE_ONE_HANDED0-23,26-34,35
FullscreenMagnificationFEATURE_FULLSCREEN_MAGNIFICATION0-12,15-23,26-27,29-31,33-35
ImePlaceholderFEATURE_IME_PLACEHOLDER13-14

5.生成DisplayArea层级结构

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/73990.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue.draggable浅尝

介绍 Vue.Draggable是一款基于Sortable.js实现的vue拖拽插件。支持移动设备、拖拽和选择文本、智能滚动&#xff0c;可以在不同列表间拖拽、不依赖jQuery为基础、vue 2过渡动画兼容、支持撤销操作&#xff0c;总之是一款非常优秀的vue拖拽组件。本篇将介绍如何搭建环境及简单的…

Python爬虫之解决浏览器等待与代理隧道问题

作为专业爬虫程序员&#xff0c;我们往往需要应对一些限制性挑战&#xff0c;比如浏览器等待和使用代理隧道。在Python爬虫开发中&#xff0c;这些问题可能会导致我们的爬虫受阻。本文将为你分享解决这些问题的方案&#xff0c;帮助你顺利应对浏览器等待和代理隧道的挑战&#…

jeecg-boot批量导入问题注意事项

现象&#xff1a; 由于批量导入数据速度很快&#xff0c; 因为数据库中的create time字段的时间可能一样&#xff0c;并且jeecg框架自带的是根据生成时间排序&#xff0c; 因此在前端翻页查询的时候&#xff0c;数据每次排序可能会不一样&#xff0c; 会出现第一页已经出现过一…

分类预测 | MATLAB实现BO-BiGRU贝叶斯优化双向门控循环单元多输入分类预测

分类预测 | MATLAB实现BO-BiGRU贝叶斯优化双向门控循环单元多输入分类预测 目录 分类预测 | MATLAB实现BO-BiGRU贝叶斯优化双向门控循环单元多输入分类预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.Matlab实现BO-BiGRU贝叶斯优化双向门控循环单元多特征分…

dirsearch_暴力扫描网页结构

python3 dirsearch 暴力扫描网页结构&#xff08;包括网页中的目录和文件&#xff09; 下载地址&#xff1a;https://gitee.com/xiaozhu2022/dirsearch/repository/archive/master.zip 下载解压后&#xff0c;在dirsearch.py文件窗口&#xff0c;打开终端&#xff08;任务栏…

Linux命名管道进程通信

文章目录 前言一、什么是命名管道通信二、创建方式三、代码示例四、文件进程通信总结 前言 命名管道 是实现进程间通信的强大工具&#xff0c;它提供了一种简单而有效的方式&#xff0c;允许不同进程之间进行可靠的数据交换。不仅可以在同一主机上的不相关进程间进行通信&…

2023年国赛数学建模思路 - 复盘:光照强度计算的优化模型

文章目录 0 赛题思路1 问题要求2 假设约定3 符号约定4 建立模型5 模型求解6 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 问题要求 现在已知一个教室长为15米&#xff0c;宽为12米&…

【JavaScript】match用法 | 正则匹配

match正则匹配 var e "www.apple.com:baidu.com" var match e.match(/com/g) console.log("match: "match);> "match: com,com"match返回值问题 match的返回值是一个数组 数组的第0个元素是与整个正则表达式匹配的结果 数组的第1个元素是…

【新品发布】ChatWork企业知识库系统源码

系统简介 基于前后端分离架构以及Vue3、uni-app、ThinkPHP6.x、PostgreSQL、pgvector技术栈开发&#xff0c;包含PC端、H5端。 ChatWork支持问答式和文档式知识库&#xff0c;能够导入txt、doc、docx、pdf、md等多种格式文档。 导入数据完成向量化训练后&#xff0c;用户提问…

查看单元测试用例覆盖率新姿势:IDEA 集成 JaCoCo

1、什么是 IDEA IDEA 全称 IntelliJ IDEA&#xff0c;是 Java 编程语言开发的集成环境。IntelliJ 在业界被公认为最好的 Java 开发工具&#xff0c;尤其在智能代码助手、代码自动提示、重构、JavaEE 支持、各类版本工具(git、SVN 等)、JUnit、CVS 整合、代码分析、 创新的 GUI…

[NDK]从Opengles到Vulkan-基础篇(2)-运行配置

上一篇我们介绍了Opengl和Vulkan运行环境的不同。 引入Opengles,我们需要做的是,在Cmakes中配置动态库引入。 使用opengles2就用GLESv2,用es3就用GLESv3,而EGL需要使用配置EGL环境 这里两个比较基础的东西是EGL和GLES的库引入。 es2只要Android 4.0就开始支持,es3是4.4开…

opencv图片灰度二值化

INCLUDEPATH D:\work\opencv_3.4.2_Qt\include LIBS D:\work\opencv_3.4.2_Qt\x86\bin\libopencv_*.dll #include <iostream> #include<opencv2/opencv.hpp> //引入头文件using namespace cv; //命名空间 using namespace std;//opencv这个机器视…

共识算法初探

共识机制的背景 加密货币都是去中心化的&#xff0c;去中心化的基础就是P2P节点众多&#xff0c;那么如何吸引用户加入网络成为节点&#xff0c;有那些激励机制&#xff1f;同时&#xff0c;开发的重点是让多个节点维护一个数据库&#xff0c;那么如何决定哪个节点写入&#x…

通过版本号控制强制刷新浏览器或清空浏览器缓存

背景介绍 在我们做 web 项目时&#xff0c;经常会遇到一个问题就是&#xff0c;需要 通知业务人员&#xff08;系统用户&#xff09;刷新浏览器或者清空浏览器 cookie 缓存的情况。 而对于用户而言&#xff0c;很多人一方面不懂如何操作&#xff0c;另一方面由于执行力问题&am…

【C语言】const修饰普通变量和指针

大家好&#xff0c;我是苏貝&#xff0c;本篇博客是系列博客每日一题的第一篇&#xff0c;本系列的题都不会太难&#xff0c;如果大家对这种系列的博客感兴趣的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 文章目录 一.const修饰普通变量二.const修饰指…

Docker容器与虚拟化技术:Docker架构、镜像管理

目录 一、理论 1.Doker概述 2.Docker核心概念 3.Docker安装 4.Docker的镜像管理命令 二、实验 1.Docker安装 2.查看Docker信息 3.Docker的镜像管理命令 三、问题 1.如何注册Docker账号 2.如何设置Docker公共存储库 四、总结 一、理论 1.Doker概述 (1) IT架构 裸…

助力青少年科技创新人才培养,猿辅导投资1亿元设立新基金

近日&#xff0c;在日本千叶县举办的2023年第64届国际数学奥林匹克&#xff08;IMO&#xff09;竞赛公布比赛结果&#xff0c;中国队连续5年获得团体第一。奖牌榜显示&#xff0c;代表中国参赛的6名队员全部获得金牌。其中&#xff0c;猿辅导学员王淳稷、孙启傲分别以42分、39分…

LLaMA长度外推高性价比trick:线性插值法及相关改进源码阅读及相关记录

前言 最近&#xff0c;开源了可商用的llama2&#xff0c;支持长度相比llama1的1024&#xff0c;拓展到了4096长度&#xff0c;然而&#xff0c;相比GPT-4、Claude-2等支持的长度&#xff0c;llama的长度外推显得尤为重要&#xff0c;本文记录了三种网络开源的RoPE改进方式及相…

ArcGIS Pro 基础安装与配置介绍

ArcGIS Pro ArcGIS Pro作为ESRI面向新时代的GIS产品&#xff0c;它在原有的ArcGIS平台上继承了传统桌面软件&#xff08;ArcMap&#xff09;的强大的数据管理、制图、空间分析等能力&#xff0c;还具有其独有的特色功能&#xff0c;例如二三维融合、大数据、矢量切片制作及发布…

用vim打开后中文乱码怎么办

Vim中打开文件乱码主要是文件编码问题。用户可以参考如下解决方法。 1、用vim打开.vimrc配置文件 vim ~/.vimrc**注意&#xff1a;**如果用户根目录下没有.vimrc文件就把/etc/vim/vimrc文件复制过来直接用 cp /etc/vim/vimrc ~/.vimrc2、在.vimrc中加入如下内容 set termen…