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.hqwc.cn/news/67079.html

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

相关文章

玩赚音视频开发高阶技术——FFmpeg

随着移动互联网的普及&#xff0c;人们对音视频内容的需求也不断增加。无论是社交媒体平台、电商平台还是在线教育&#xff0c;都离不开音视频的应用。这就为音视频开发人员提供了广阔的就业机会。根据这些年来网站上的音视频开发招聘需求来看&#xff0c;音视频开发人员的需求…

ChatGPT or BingChat

你相信我们对大模型也存在「迷信权威」吗&#xff1f; ChatGPT 的 GPT-4 名声在外&#xff0c;我们就不自觉地更相信它&#xff0c;优先使用它。但我用 ChatALL 比较 AI 大模型们这么久&#xff0c;得到的结论是&#xff1a; ChatGPT GPT-4 在大多数情况下确实是最强&#xf…

推断统计(独立样本t检验)

这里我们是采用假设检验中的独立样本t 检验来比较两个独立正态总体均值之间是否存在显著性差异&#xff0c;以比较城市与农村孩子的心理素质是否有显著差异为例 。 这里我们首先是假设城市孩子与农村孩子心理素质无显著差异&#xff0c;但是此时方差是否齐性是未知的&#xff0…

使用 AndroidX 增强 WebView 的能力

在App开发过程中&#xff0c;为了在多个平台上保持一致的用户体验和提高开发效率&#xff0c;许多应用程序选择使用 H5 技术。在 Android 平台上&#xff0c;通常使用 WebView 组件来承载 H5 内容以供展示。 一.WebView 存在的问题 自 Android Lollipop 起&#xff0c;WebVie…

了解 Langchain️是个啥?:第 1 部分

一、说明 在日常生活中&#xff0c;我们主要致力于构建端到端的应用程序。我们可以使用许多自动 ML 平台和 CI/CD 管道来自动化 ml 管道。我们还有像Roboflow和Andrew N.G.的登陆AI这样的工具来自动化或创建端到端的计算机视觉应用程序。 如果我们想在OpenAI或拥抱脸的帮助下创…

文本挖掘 day5:文本挖掘与贝叶斯网络方法识别化学品安全风险因素

文本挖掘与贝叶斯网络方法识别化学品安全风险因素 1. Introduction现实意义理论意义提出方法&#xff0c;目标 2. 材料与方法2.1 数据集2.2 数据预处理2.3 关键字提取2.3.1 TF-IDF2.3.2 改进的BM25——BM25WBM25BM25W 2.3.3 关键词的产生(相关系数) 2.4 关联规则分析2.5 贝叶斯…

vue学习笔记

1.官网 v2官网 https://v2.cn.vuejs.org/ v3官网 https://cn.vuejs.org/ 2.vue引入 在线引入 <script src"https://cdn.jsdelivr.net/npm/vue2.7.14/dist/vue.js"></script> 下载引入(下载链接) https://v2.cn.vuejs.org/js/vue.js 3.初始化渲…

VictoriaMetrics部署及vmalert集成钉钉告警

1、部署VictoriaMetrics cd /usr/local wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.65.0/victoria-metrics-amd64-v1.65.0.tar.gz mkdir victoria-metrics && tar -xvzf victoria-metrics-amd64-v1.65.0.tar.gz && \ mv …

JVM 内存结构

1、方法区&#xff08;线程共享&#xff09; 存储静态变量(静态方法、变量、代码块)、常量池、类信息 2、堆信息&#xff08;线程共享&#xff09; 存储实例对象&#xff0c;例如 new 出来的对象信息 A a1 new A() 3、虚拟机栈&#xff08;线程隔离&#xff09; 每个线程的都有…

试岗第一天问题

1、公司的一个项目拉下来 &#xff0c;npm i 不管用显示 后面百度 使用了一个方法 虽然解决 但是在增加别的依赖不行&#xff0c;后面发现是node版本过高&#xff0c;更换node版本解决。 2、使用插件动态的使数字从0到100&#xff08;vue-animate-number插件&#xff09; 第一…

(css)点击前隐藏icon图表 点击后显示

(css)点击前隐藏icon图表 点击后显示 效果 html <liv-for"(item,index) in sessionList":key"index"class"liClass":class"{ active: change2 index }"tabindex"2">...<el-tooltip class"item" effec…

蓝牙入耳式耳机老是滑出来,耳朵小适合戴什么样的骨传导耳机

最近体验了几款骨传导耳机&#xff0c;分享下我的使用感受。首先说一下为什么要选择骨传导耳机&#xff0c;我之前是使用入耳式耳机&#xff0c;戴久了耳朵会疼&#xff0c;而且晚上睡觉不能戴。于是就考虑骨传导耳机&#xff0c;因为骨传导耳机在传声的过程中不需要经过耳膜&a…