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 correctlymDisplayAreaPolicy = 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 {@Overridepublic 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.创建HierarchyBuilderfinal HierarchyBuilder rootHierarchy = new HierarchyBuilder(root);// Set the essential containers (even if the display doesn't support IME).//3.1添加ImeContainer到HierarchyBuilder//3.2创建并保存默认TaskDisplayArea到HierarchyBuilderrootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList);if (content.isTrusted()) {// Only trusted display can have system decorations.//4.为HierarchyBuilder添加FeatureconfigureTrustedHierarchyBuilder(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<>();@Nullableprivate 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 thingreturn  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 volumereturn  22;case TYPE_SYSTEM_OVERLAY:// the on-screen volume indicator and controller shown when the user// changes the device volumereturn  canAddInternalSystemWindow ? 23 : 10;case TYPE_NAVIGATION_BAR:// the navigation bar, if available, shows atop most thingsreturn  24;case TYPE_NAVIGATION_BAR_PANEL:// some panels (e.g. search) need to show on top of the navigation barreturn  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 dialogsreturn  canAddInternalSystemWindow ? 27 : 9;case TYPE_MAGNIFICATION_OVERLAY:// used to highlight the magnified portion of a displayreturn  28;case TYPE_DISPLAY_OVERLAY:// used to simulate secondary display devicesreturn  29;case TYPE_DRAG:// the drag layer: input for drag-and-drop is associated with this window,// which sits above all other focusable windowsreturn  30;case TYPE_ACCESSIBILITY_OVERLAY:// overlay put by accessibility services to intercept user interactionreturn  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 layerreturn  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层级结构

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VSCODE[配置ssh免密远程登录]

配置ssh免密远程登录 本文摘录于&#xff1a;https://blog.csdn.net/qq_44571245/article/details/123031276只是做学习备份之用&#xff0c;绝无抄袭之意&#xff0c;有疑惑请联系本人&#xff01; 这里要注意如下几个地方: 1.要进入.ssh目录创建文件: 2.是拷贝带"ssh-…

【LeetCode】55. 跳跃游戏 - 贪婪算法

目录标题 2023-8-10 16:27:05 55. 跳跃游戏 2023-8-10 16:27:05 class Solution {public boolean canJump(int[] nums) {int n nums.length;int arrivalLocation 0;for (int i 0; i < n; i) {if (i < arrivalLocation) {arrivalLocation Math.max(arrivalLocation,…

手把手教你如何零成本搭建网站实现内网穿透从而创建自己的数据隧道

手把手教你如何零成本搭建网站实现内网穿透从而创建自己的数据隧道 文章目录 手把手教你如何零成本搭建网站实现内网穿透从而创建自己的数据隧道前言1. 安装网站运行和发布必备软件2. 安装PHPStudy3. 安装wordpress4. 进入wordpress安装程序&#xff0c;进行网页编辑和设置5. 安…

Windows Oracle21C与PLSQL Developer 15配置

1、下载Oracle21c并安装 下载地址&#xff1a;https://www.oracle.com/database/technologies/oracle21c-windows-downloads.html 2、下载PLSQL Developer 15并安装 下载地址&#xff1a;https://www.allroundautomations.com/products/pl-sql-developer/#pricing 3、配置O…

Claude 2、ChatGPT、Google Bard优劣势比较

​Claude 2&#xff1a; 优势&#xff1a;Claude 2能够一次性处理多达10万个tokens&#xff08;约7.5万个单词&#xff09;。 tokens数量反映了模型可以处理的文本长度和上下文数量。tokens越多&#xff0c;模型理解语义的能力就越强&#xff09;。它在法律、数学和编码等多个…

K8S MetalLB LoadBalancer

1. 简介 kubernetes集群没有L4负载均衡&#xff0c;对外暴漏服务时&#xff0c;只能使用nodePort的方式&#xff0c;比较麻烦&#xff0c;必须要记住不同的端口号。 LoadBalancer&#xff1a;使用云提供商的负载均衡器向外部暴露服务&#xff0c;外部负载均衡器可以将流量路由…

Leaflet入门,Leaflet如何自定义版权信息,以vue2-leaflet修改自定义版权为例

前言 本章讲解使用Leaflet的vue2-leaflet或者vue-leaflet插件来实现自定义版权信息的功能。 # 实现效果演示 见图片右下角版权信息 vue如何使用Leaflet vue2如何使用:《Leaflet入门,如何使用vue2-leaflet实现vue2双向绑定式的使用Leaflet地图,以及初始化后拿到leaflet对象…

Java获取指定文件夹下目录下所有视频并复制到另一个地方

import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.StandardCopyOption;public class VideoCopier {public static void main(String[] args) {// 指定源文件夹路径和目标文件夹路径String sourceFolderPath "path/to…

OSI参考模型及TCP/IP协议栈

一、网络概述 1.1、什么是网络&#xff1f; 1、网络的本质就是实现资源共享 2、将各个系统联系到一起&#xff0c;形成信息传递、接收、共享的信息交互平台 1.2、典型的园区网拓扑 1.3、网络历史发展&#xff0c;ARPA和ARPANET 1、1969年&#xff0c;美国国防部高级研究计…

8.10论文阅读

文章目录 The multimodal MRI brain tumor segmentation based on AD-Net摘要本文方法损失函数 实验结果 max-vit - unet:多轴注意力医学图像分割摘要本文方法实验结果 The multimodal MRI brain tumor segmentation based on AD-Net 摘要 基于磁共振成像(MRI)的多模态胶质瘤…

JavaEE——网络编程(UDP套接字编程)

文章目录 一、简单理解Socket 套接字二、UDP 数据报套接字编程三、编写简单的 UDP 版本服务器客户端1. 编写 UDP 版本的回显服务器回显服务器整体代码罗列 2. 编写 UDP 版本的回显客户端回显客户端整体代码罗列 四、总结与代码运行结果解释 一、简单理解Socket 套接字 概念&am…

100天精通Golang(基础入门篇)——第18天:深入解析Go语言中的结构体

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to Golang Language.✨✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1…

半导体芯片介质膜层膜层膜厚测量仪

镀膜是半导体芯片制备过程中的重要步骤。在一个完整的CMOS工艺流程中&#xff0c;介质膜层(保护层、外延层、光刻胶和栅极氧化物等)与金属沉积层交替出现。随着芯片工艺节点不断进步&#xff0c;介质膜层也变得越来越复杂&#xff0c;在7nm工艺中&#xff0c;所需测量的介质膜堆…

AppStream下载元数据失败

错误&#xff1a;为仓库 AppStream 下载元数据失败 : Cannot prepare internal mirrorlist: No URLs in mirrorlist 目录 一、域名解析 二、CentOS-AppStream.repo 三、CentOS-Base.repo 四、CentOS-Extras.repo 五、rpm更新 一、域名解析 先验证 ping www.baidu.com 不…

STM32基于CubeIDE和HAL库 基础入门学习笔记:物联网项目开发流程和思路

文章目录&#xff1a; 第一部分&#xff1a;项目开始前的计划与准备 1.项目策划和开发规范 1.1 项目要求文档 1.2 技术实现文档 1.3 开发规范 2.创建项目工程与日志 第二部分&#xff1a;调通硬件电路与驱动程序 第三部分&#xff1a;编写最基础的应用程序 第四部分&…

基于dbn+svr的交通流量预测,dbn详细原理

目录 背影 DBN神经网络的原理 DBN神经网络的定义 受限玻尔兹曼机(RBM) DBN+SVR的交通流量预测 基本结构 主要参数 数据 MATALB代码 结果图 展望 背影 DBN是一种深度学习神经网络,拥有提取特征,非监督学习的能力,是一种非常好的分类算法,本文将DBN+SVR用于交通流量预测…

怎样才能免费使用Qt开发闭源商业软件?

Qt 是一个跨平台的应用程序开发框架&#xff0c;其使用遵循 GNU Lesser General Public License&#xff08;LGPL&#xff09;开源许可协议。根据 LGPL 许可协议&#xff0c;您可以将 Qt 用于闭源商业软件&#xff0c;但是您需要满足以下条件&#xff1a; 1. 在您的软件中使用…

③ vue组件

vue组件创建 在App.vue中添加。 技巧&#xff1a;先import&#xff0c;把vue组件地址写出来。然后在template中写名字。剩下的就自动生成。要看下import有没有多生成什么。 注意1&#xff1a; 注意2&#xff1a; 不只是能在App.vue中引入组件。任意组件中都可以引用其他组件…

SRE之前端服务器的负载均衡

写在前面 今天和小伙伴们分享一些前端服务器的负载均衡技术内容为结合《 SRE Google运维解密》 整理&#xff1a; 涉及DNS 负载均衡VIP 负载均衡反向代理负载均衡 理解不足小伙伴帮忙指正 傍晚时分&#xff0c;你坐在屋檐下&#xff0c;看着天慢慢地黑下去&#xff0c;心里寂寞…

Zabbix监控系统详解及配置

前言 作为一个运维&#xff0c;需要会使用监控系统查看服务器状态以及网站流量指标&#xff0c;利用监控系统的数据去了解上线发布的结果&#xff0c;和网站的健康状态。利用一个优秀的监控软件&#xff0c;我们可以&#xff1a; 通过一个友好的界面进行浏览整个网站所有的服务…