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.mzph.cn/news/36781.shtml

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

相关文章

日常BUG —— Java判空注解

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;日常BUG、BUG、问题分析☀️每日 一言 &#xff1a;存在错误说明你在进步&#xff01; 一. 问题描述 问题一&#xff1a; 在使用Java自带的注解NotNull、NotEmpty、NotBlank时报错&#xff0c;…

CentOS8安装Git

错误1. 执行yum命令报错 【错误&#xff1a;Invalid configuration value: failovermethodpriority in /etc/yum.repos.d/CentOS-epel.repo; 配置&#xff1a;ID 为 "failovermethod" 的 OptionBinding 不存在】 1.cd /etc/yum.repos.d 2.vim CentOS-epel.repo //…

warning: remember to run ‘libtool --finish /usr/local/1/php-7.4.29/libs

ubuntu上php7.4.33编译安装完成后警告报错&#xff0c;如下所示 # /usr/local/apache2/apr/build-1/libtool --finish /usr/local/soft/php-7.4.33/libs # vim /etc/ld.so.conf.d/local.conf /usr/local/lib /usr/lib64 # ldconfig 或者安装依赖服务&#xff0c;重新编译 #…

Linu学习笔记——常用命令

Linux 常用命令全拼&#xff1a; Linux 常用命令全拼 | 菜鸟教程 一、切换root用户 1.给root用户设置密码 sudo passwd root 2.输入密码&#xff0c;并确认密码 3.切换到root用户 su&#xff1a;Swith user(切换用户) su root 二、切换目录 目录结构&#xff1a;Linux 系…

软件测试基础篇——Linux

1、Linux系统的特征 开源免费&#xff1a; 开源&#xff1a;开放源代码&#xff0c;指的是底层的源代码是可以开放出来&#xff0c;给相关的开发者&#xff0c;根据实际的需求做出修改的。 免费&#xff1a;不花钱&#xff0c;自由传播。 ​ Linux是一种免费使用和自由传播的…

【ARM 调试】如何从 crash 信息找出问题原因

一、问题背景 粉丝在进行 ARM-A 系列软件编程时遇到以下问题&#xff0c;串口打印这段日志后就重启了&#xff0c;粉丝求助问是什么原因&#xff1f; Unhandled Exception in EL3. x30 0x0000000000b99b84 x0 0x00000000179a25b0 x1 …

NGINX组件(rewrite)

一、location匹配的规则和优先级&#xff08;*&#xff09; URI&#xff1a;统一资源标识符&#xff0c;是一种字符串标识&#xff0c;用于标识抽象的或者是物理资源&#xff1b;如&#xff1a;文件、图片、视频等 nginx中的URI匹配的是&#xff1a;网址”/“后的路径 如&…

解决Idea 多模块,maven项目是多层级文件夹的子项时无法加入git管理的问题

问题 多模块项目&#xff0c;引入模块无法做git管理&#xff0c;第一个项目没有git分支标志&#xff0c;也不能像其他项目一样右键出git选项。 解决方法 发现该模块是多层级的文件夹结构&#xff0c;也就是项目本身在一个文件夹下。应该是要管理该文件夹。 Settings-Versi…

el-select控制单选还是多选

multiple表示多选&#xff0c;:multiple-limit“1” 限制多选的条数为1&#xff0c;2就是选两个&#xff0c;依此类推。为0 就是不限制选几个 使用 allow-create 属性即可通过在输入框中输入文字来创建新的条目。注意此时 filterable 必须为真。 <el-form :inline"true…

阿里云云主机_ECS云服务器_轻量_GPU_虚拟主机详解

阿里云云主机分为云虚拟主机、云服务器ECS、轻量应用服务器、GPU云服务器、弹性裸金属服务器、专有宿主机、FPGA云服务器、高性能计算E-HPC、无影云电脑等&#xff0c;阿里云百科来详细说下阿里云云主机详解&#xff1a; 目录 阿里云云主机 云服务器ECS 轻量应用服务器 云…

我学会这些车载技术,是不是就可以进【小米】车企?

作者&#xff1a;阿刁 随着智能化和电动化的发展&#xff0c;车载开发领域的前景非常广阔。许多手机厂商也纷纷加入进来&#xff0c;华为、小米等手机巨头也相继推出新能源汽车。所以在未来&#xff0c;车载系统将成为汽车的核心部分&#xff0c;涵盖车辆的控制、信息娱乐、智能…

安装paddleSeq2.7.0版本模块-笔记

安装paddleSeq2.7.0版本模块-笔记 先安装conda和python版本 本机安装的conda 22.9.0 python2.9.12 paddle2.4.2 paddlepaddle-gpu2.4.2 cuda10.2 安装matplotlib3.5.0版本 opencv_python-4.5.4.60-cp39-cp39-win_amd64.whl 测试采用分割模型名称&#xff1a;BiSeNetv2 #BiSe…

Oracle 开发篇+Java调用OJDBC访问Oracle数据库

标签&#xff1a;JAVA语言、Oracle数据库、Java访问Oracle数据库释义&#xff1a;OJDBC是Oracle公司提供的Java数据库连接驱动程序 ★ 实验环境 ※ Oracle 19c ※ OJDBC8 ※ JDK 8 ★ Java代码案例 package PAC_001; import java.sql.Connection; import java.sql.ResultSet…

【TensorFlow】P0 Windows GPU 安装 TensorFlow、CUDA Toolkit、cuDNN

Windows 安装 TensorFlow、CUDA Toolkit、cuDNN 整体流程概述TensorFlow 与 CUDA ToolkitTensorFlow 是一个基于数据流图的深度学习框架CUDA 充分利用 NIVIDIA GPU 的计算能力CUDA Toolkit cuDNN 安装详细流程整理流程一&#xff1a;安装 CUDA Toolkit步骤一&#xff1a;获取CU…

XML 数据传输格式

目录 XML简介 一、初识XML 1.什么是 XML&#xff1f; 2.XML 和 HTML 之间的差异 3.XML 不会做任何事情 4.通过 XML 您可以发明自己的标签 5.XML 不是对 HTML 的替代 二、XML 用途 1.XML 把数据从 HTML 分离 2.XML 简化数据共享 3.XML 简化数据传输 三、XML 树结构 1.一个 XML 文…

QML HTTP 请求

作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 在 Web 开发中,实现与服务器的通信至关重要,其中 HTTP 便是最常用的方式之一。它是一种客户端 - 服务器协议,客户端向服务器发送请求,服务器则返回响应。常被用于在浏览器/客户端和 Web 服务器之间传输消…

1. 如何爬取自己的CSDN博客文章列表(获取列表)(博客列表)(手动+python代码方式)

文章目录 写在最前步骤打开chrome浏览器&#xff0c;登录网页按pagedown一直往下刷呀刷呀刷&#xff0c;直到把自己所有的博文刷出来然后我们按F12&#xff0c;点击选取元素按钮然后随便点一篇博文&#xff0c;产生如下所示代码然后往上翻&#xff0c;找到头&#xff0c;复制然…

Java-类型和变量(基于C语言的补充)

一个简单的Java程序 args){ System.out.println("Hello,world"); } }通过上述代码&#xff0c;我们可以看到一个完整的Java程序的结构&#xff0c;Java程序的结构由如下三个部分组成&#xff1a; 1.源文件&#xff08;扩展名为*.java)&#xff1a;源文件带有类的定义…

[保研/考研机试] KY7 质因数的个数 清华大学复试上机题 C++实现

描述 求正整数N(N>1)的质因数的个数。 相同的质因数需要重复计算。如1202*2*2*3*5&#xff0c;共有5个质因数。 输入描述&#xff1a; 可能有多组测试数据&#xff0c;每组测试数据的输入是一个正整数N&#xff0c;(1<N<10^9)。 输出描述&#xff1a; 对于每组数…

leetcode 6914. 翻倍以链表形式表示的数字

给你一个 非空 链表的头节点 head &#xff0c;表示一个不含前导零的非负数整数。 将链表 翻倍 后&#xff0c;返回头节点 head 。 示例 1&#xff1a; 输入&#xff1a;head [1,8,9] 输出&#xff1a;[3,7,8] 解释&#xff1a;上图中给出的链表&#xff0c;表示数字 189 。返…