Android 窗口结构(一) 窗口层级构造

  Android窗口是根据显示屏幕来管理,每个显示屏幕的窗口层级分为37层,0-36层。每层可以放置多个窗口,上层窗口覆盖下面的。
  要理解窗口的结构,需要学习下WindowContainer、RootWindowContainer、DisplayContent、TaskDisplayArea、Task、ActivityRecord、WindowToken、WindowState
WindowContainer等类。

WindowContainer类

  为直接包含窗口或者通过孩子层级形式包含窗口的类,定义了普遍功能。它作为基类被继承,像RootWindowContainer、DisplayContent、TaskDisplayArea、Task、ActivityRecord、WindowToken、WindowState都是直接或间接的继承该类。

class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
        implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable {
    ……
    // List of children for this window container. List is in z-order as the children appear on
    // screen with the top-most window container at the tail of the list.
    protected final WindowList<E> mChildren = new WindowList<E>();        	
    ……
        }

  简单看一下类的定义,泛型参数E是继承WindowContainer,它是孩子类型。WindowList是继承ArrayList,这样就能通过mChildren ,构建一种树形结构。

窗口结构层级相关类

  先上一张没添加特色模式窗口结构图:
Android 窗口结构(一) 窗口层级构造_第1张图片

没添加特色模式窗口结构图

  该图是未添加特色模式时的结构图,添加特色模式之后的结构,更复杂。
  RootWindowContainer:根窗口容器,树的根是它。通过它遍历寻找,可以找到窗口树上的窗口。它的孩子是DisplayContent。
  DisplayContent:该类是对应着显示屏幕的,Android是支持多屏幕的,所以可能存在多个DisplayContent对象。上图只画了一个对象的结构,其他对象的结构也是和画的对象的结构是相似的。
  TaskDisplayArea:它为DisplayContent的孩子,对应着窗口层次的第2层。第2层作为应用层,看它的定义:int APPLICATION_LAYER = 2,应用层的窗口是处于第2层。TaskDisplayArea的孩子是Task类,其实它的孩子类型也可以是TaskDisplayArea。而Task的孩子则可以是ActivityRecord,也可以是Task。
  Tokens:它为DisplayContent的孩子,它的孩子是WindowToken。而WindowToken的孩子则为WindowState对象。WindowState是对应着一个窗口的。结构图中,DisplayContent不止包含一个Tokens,还有两个。其实ImeContainer也是继承自Tokens。
  ImeContainer:它也为DisplayContent的孩子,它是输入法窗口的容器,它的孩子是WindowToken类型。WindowToken的孩子为WindowState类型,而WindowState类型则对应着输入法窗口。
  Task:任务,它的孩子可以是Task,也可以是ActivityRecord类型。
  ActivityRecord:是对应着应用进程中的Activity的。ActivityRecord是继承WindowToken的,它的孩子类型为WindowState。
  WindowState:WindowState是对应着一个窗口的。
  结构图中,DisplayContent有5个孩子。图中从上到下,第一个是Tokens,对应着窗口图层0、1。第二个是TaskDisplayArea,对应着窗口图层2。第三个是Tokens,对应着窗口图层3到14。第四个是ImeContainer,对应着窗口图层15到16。第五个是Tokens,对应着窗口图层17到36。

构建窗口结构

  下面结合代码来看下上面的窗口结构的构造。
  RootWindowContainer的构造是在WindowManagerService中,

    private WindowManagerService(Context context, InputManagerService inputManager,
            boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
            ActivityTaskManagerService atm, DisplayWindowSettingsProvider
            displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
            Supplier<Surface> surfaceFactory,
            Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
            ……
            mRoot = new RootWindowContainer(this);
			……
    }

  可见RootWindowContainer对象作为WindowManagerService的成员变量mRoot 存在。
  在ActivityTaskManagerService类中,会调用setWindowManager(WindowManagerService wm)方法,

    public void setWindowManager(WindowManagerService wm) {
        synchronized (mGlobalLock) {
            mWindowManager = wm;
            mRootWindowContainer = wm.mRoot;
            mTempConfig.setToDefaults();
            mTempConfig.setLocales(LocaleList.getDefault());
            mConfigurationSeq = mTempConfig.seq = 1;
            mRootWindowContainer.onConfigurationChanged(mTempConfig);
            mLockTaskController.setWindowManager(wm);
            mTaskSupervisor.setWindowManager(wm);
            mRootWindowContainer.setWindowManager(wm);
        }
    }

  ActivityTaskManagerService的成员变量mRootWindowContainer 也赋值为RootWindowContainer根对象。最后会调用RootWindowContainer的setWindowManager(wm)方法:

    void setWindowManager(WindowManagerService wm) {
        mWindowManager = wm;
        mDisplayManager = mService.mContext.getSystemService(DisplayManager.class);
        mDisplayManager.registerDisplayListener(this, mService.mUiHandler);
        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);

        final Display[] displays = mDisplayManager.getDisplays();
        for (int displayNdx = 0; displayNdx < displays.length; ++displayNdx) {
            final Display display = displays[displayNdx];
            final DisplayContent displayContent = new DisplayContent(display, this);
            addChild(displayContent, POSITION_BOTTOM);
            if (displayContent.mDisplayId == DEFAULT_DISPLAY) {
                mDefaultDisplay = displayContent;
            }
        }
        calculateDefaultMinimalSizeOfResizeableTasks();

        final TaskDisplayArea defaultTaskDisplayArea = getDefaultTaskDisplayArea();
        defaultTaskDisplayArea.getOrCreateRootHomeTask(ON_TOP);
        positionChildAt(POSITION_TOP, defaultTaskDisplayArea.mDisplayContent,
                false /* includingParents */);
    }

  从上面看出,通过屏幕管理对象mDisplayManager得到所有的显示屏幕,然后构造DisplayContent对象,再通过addChild(displayContent, POSITION_BOTTOM)方法将DisplayContent对象添加到RootWindowContainer根对象的树状结构中。
  默认显示屏幕的mDisplayId 是DEFAULT_DISPLAY,看下它的值(Display类 public static final int DEFAULT_DISPLAY = 0),mDisplayId 为0作为基本显示屏幕。
  接着通过getDefaultTaskDisplayArea()得到默认屏幕的TaskDisplayArea,在调用它的getOrCreateRootHomeTask(ON_TOP)创建一个根Home任务。最后把默认屏幕放在RootWindowContainer根对象的孩子的最上面。
  接下来看看DisplayContent对象的构造函数。

DisplayContent对象的构造

    // Contains all IME window containers. Note that the z-ordering of the IME windows will depend
    // on the IME target. We mainly have this container grouping so we can keep track of all the IME
    // window containers together and move them in-sync if/when needed. We use a subclass of
    // WindowContainer which is omitted from screen magnification, as the IME is never magnified.
    // TODO(display-area): is "no magnification" in the comment still true?
    private final ImeContainer mImeWindowsContainer = new ImeContainer(mWmService);    
    /**
     * Create new {@link DisplayContent} instance, add itself to the root window container and
     * initialize direct children.
     * @param display May not be null.
     * @param root {@link RootWindowContainer}
     */
    DisplayContent(Display display, RootWindowContainer root) {
    	……
        // Setup the policy and build the display area hierarchy.
        mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(
                mWmService, this /* content */, this /* root */, mImeWindowsContainer);	
		……
    }		

  这里将窗口构建的相关代码贴出来,
  mWmService是WindowManagerService对象,它的getDisplayAreaPolicyProvider()得到

    DisplayAreaPolicy.Provider getDisplayAreaPolicyProvider() {
        return mDisplayAreaPolicyProvider;
    }

  mDisplayAreaPolicyProvider是WindowManagerService对象的成员变量,它初始化在WindowManagerService对象的初始化方法中:

    private WindowManagerService(Context context, InputManagerService inputManager,
            boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
            ActivityTaskManagerService atm, DisplayWindowSettingsProvider
            displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
            Supplier<Surface> surfaceFactory,
            Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {     
            …………   
        mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources(
                mContext.getResources());
           …………
           }
    public interface Provider {
    …………
            static Provider fromResources(Resources res) {
            String name = res.getString(
                    com.android.internal.R.string.config_deviceSpecificDisplayAreaPolicyProvider);
            if (TextUtils.isEmpty(name)) {
                return new DisplayAreaPolicy.DefaultProvider();
            }
            try {
                return (Provider) Class.forName(name).newInstance();
            } catch (ReflectiveOperationException | ClassCastException e) {
                throw new IllegalStateException("Couldn't instantiate class " + name
                        + " for config_deviceSpecificDisplayAreaPolicyProvider:"
                        + " make sure it has a public zero-argument constructor"
                        + " and implements DisplayAreaPolicy.Provider", e);
            }
        }
    }

  可以看到mDisplayAreaPolicyProvider 的具体类型是可以在系统资源文件中配置的,资源字符串属性为config_deviceSpecificDisplayAreaPolicyProvider,如果为空,类型则为DefaultProvider类型。目前查看,资源文件里没有配置字符值。所以mDisplayAreaPolicyProvider类型则为DefaultProvider类型。
  接着调用DefaultProvider的instantiate()方法,该方法在文件platform\frameworks\base\services\core\java\com\android\server\wm\DisplayAreaPolicy.java中

    /** 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) {
            final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService,
                    "DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);
            final List<TaskDisplayArea> tdaList = new ArrayList<>();
            tdaList.add(defaultTaskDisplayArea);

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

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

  首先新建一个TaskDisplayArea 对象defaultTaskDisplayArea ,看其名字叫默认TaskDisplayArea。接着创建HierarchyBuilder 对象rootHierarchy 。rootHierarchy 将imeContainer(输入法窗口容器)和刚才新建的defaultTaskDisplayArea 都设置到它的成员变量里面。
  接着再判断显示屏是否是可信任的content.isTrusted(),一般系统创建的都设置为可信任的,包括默认显示屏幕。会调用configureTrustedHierarchyBuilder(rootHierarchy, wmService, content)方法进行配置,这个方法里面主要是添加一些特色模式。
  最后,也是采用建造者模式新建DisplayAreaPolicyBuilder对象,然后将前面设置好的rootHierarchy对象设置到自己成员变量中,最后调用build()方法,进行建造。构造完成之后,返回的是一个Result对象,它继承DisplayAreaPolicy。所以从这里可知,DisplayContent的mDisplayAreaPolicy 是Result对象。

1、HierarchyBuilder 对象设置
    static class HierarchyBuilder {
    	……
        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;
        } 
        /** Adds {@link Feature} that applies to layers under this container. */
        HierarchyBuilder addFeature(DisplayAreaPolicyBuilder.Feature feature) {
            mFeatures.add(feature);
            return this;
        }
         /**
         * 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;
        }

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

  rootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList)就是将imeContainer设置到rootHierarchy对象的成员变量mImeContainer,将tdaList添加到成员变量mTaskDisplayAreas。

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

  可见,主要采用特色模式建造类Feature.Builder,设置属性,设置完成之后,添加到HierarchyBuilder 类对象rootHierarchy中。
  添加的特色模式有FEATURE_WINDOWED_MAGNIFICATION、FEATURE_HIDE_DISPLAY_CUTOUT、FEATURE_ONE_HANDED_BACKGROUND_PANEL、FEATURE_ONE_HANDED、FEATURE_FULLSCREEN_MAGNIFICATION、FEATURE_IME_PLACEHOLDER。只有在屏幕是默认基础的屏幕情况下,才会添加FEATURE_HIDE_DISPLAY_CUTOUT、FEATURE_ONE_HANDED_BACKGROUND_PANEL、FEATURE_ONE_HANDED这三种。
  在设置特色模式的时候,还会设置对哪些窗口图层产生影响。窗口图层和窗口类型是相关的,可以通过窗口类型得到窗口所在的图层层级。先看看特色模式建造者类:

特色模式建造者类
Builder
WindowManagerPolicy mPolicy
String mName
int mId
boolean[] mLayers
NewDisplayAreaSupplier mNewDisplayAreaSupplier = DisplayArea::new
boolean mExcludeRoundedCorner = true
Builder(WindowManagerPolicy policy, String name, int id)
all()
and(int... types)
except(int... types)
upTo(int typeInclusive)
setNewDisplayAreaSupplier(NewDisplayAreaSupplier newDisplayAreaSupplier)
setExcludeRoundedCornerOverlay(boolean excludeRoundedCorner)
build()
set(int type, boolean value)
layerFromType(int type, boolean internalWindows)

  mName和mId是特色模式的名字和Id。
  mLayers数组大小是37,对应着窗口层级。如果对应的层级设置为true,就是该模式对该窗口层级产生影响。
  mNewDisplayAreaSupplier是如何新建DisplayArea,默认是DisplayArea::new。
  mPolicy是和窗口类型和图层层级转化有关
  mExcludeRoundedCorner是指是否排除圆角层,默认是排除的
  set(int type, boolean value),layerFromType(int type, boolean internalWindows)是通过图层类型得到图层数,然后设置图层数对应的mLayers数组中的值。
  特色模型类建造类中的all()、and()、except()、upTo(),他们都是为了设置对应的窗口层级。all()是所有的层级都设置为true。and()是将参数中对应的层级设置为true,except()是将参数中对应的层级设置为false,就是去除掉该层级。upTo()则是将第0层直到参数指定的层级都设置为true。
  build()方法就是新建Feature对象,在其中会判断mExcludeRoundedCorner,如果为true,则将mLayers数组中对应的值设为false,目前圆角层是在最上层36层。
  窗口类型和层级的转化是通过layerFromType(int type, boolean internalWindows)实现,它则是mPolicy.getWindowLayerFromTypeLw(type, internalWindows)方法实现的,mPolicy是WindowManagerPolicy类型,看下代码:

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

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

  可以看到,窗口类型与图层层级对应关系。最大是getMaxWindowLayer(),它的值是36。该方法里面并没有提到0层,但是代码构造窗口层级的时候,是从0层开始的。type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW,是APPLICATION_LAYER层,也就是第二层。FIRST_APPLICATION_WINDOW 是1,LAST_APPLICATION_WINDOW是99。在这之间的窗口类型都是属于窗口应用层。窗口层级数值越大,它就会在上面,会覆盖下层的窗口。
  回到configureTrustedHierarchyBuilder()中,可以看到

特色模式 影响窗口图层
FEATURE_WINDOWED_MAGNIFICATION 0-31
FEATURE_HIDE_DISPLAY_CUTOUT 0-16、18、20-23、26-35
FEATURE_ONE_HANDED_BACKGROUND_PANEL 0-1
FEATURE_ONE_HANDED 0-23、26-35
FEATURE_FULLSCREEN_MAGNIFICATION 0-14、17-23、26-27、29-31、33-35
FEATURE_IME_PLACEHOLDER 15-16

  这些影响到的图层数都是根据上面提到的几个方法里面得出来的。并且如果是默认显示屏幕,会将上述6个特色模式都加入到HierarchyBuilder对象中。
  其中需要注意一点的是,在添加FEATURE_WINDOWED_MAGNIFICATION时,它是会设置建造者对象的mNewDisplayAreaSupplier 为DisplayArea.Dimmable::new。等到它构造DisplayArea对象的时候,它的实际对象类型是DisplayArea.Dimmable。它可以控制变暗的显示区域。

3 构造窗口层级

  构造层级的方法在DisplayAreaPolicyBuilder类的build(WindowManagerService wmService)里面:

    Result build(WindowManagerService wmService) {
        validate();

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

  这个方法主要就是调用mRootHierarchyBuilder.build(mDisplayAreaGroupHierarchyBuilders)构造层级。mDisplayAreaGroupHierarchyBuilders的大小为0,如果mSelectRootForWindowFunc 没有设置值的话,设置为DefaultSelectRootForWindowFunction对象。最后新生成一个Result对象返回。

HierarchyBuilder的build(@Nullable List displayAreaGroupHierarchyBuilders)

  这里说一下,是对于默认屏幕来分析,就是设置了上面说的六种特色模式。
该方法代码挺长,分段阅读:

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

  maxWindowLayerCount 的值为37,代表图层总数。displayAreaForLayer 数组代表每一层的叶子Tokens对象。等到下面会看到,图层结构是个树结构,它则是存储的是叶子节点的对应内容。featureAreas 里面根据特色模式。存储对应特色模式里面的窗口容器。
  第二段代码:

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

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

  这里首先需要介绍下PendingArea类,它是构建窗口树的主要类。

PendingArea
int mMinLayer
ArrayList< PendingArea> mChildren
Feature mFeature
PendingArea mParent
int mMaxLayer
DisplayArea mExisting
boolean mSkipTokens = false
instantiateChildren()
createArea()

  它的mParent指向它的父PendingArea,mChildren里面是它的孩子PendingArea。mMinLayer是对应的窗口图层最小层,mMaxLayer是最大层。mExisting与mSkipTokens和createArea()相关。如果mExisting存在,就直接使用它,如果不存在,会新建DisplayArea;但是mSkipTokens为true,就不新建直接返回null。
  构建的树结构是使用mParent和mChildren实现的。
  现在就按照第二段代码分析一下,首先新建一个根PendingArea对象root,并且将areaForLayer数组里都填充root,这就是将各个图层的PendingArea对象都指向root。
  再接着就是两层循环,第一层循环是遍历特色模式,第二层是遍历窗口图层。可以看到,在第二层循环中,如果特色模式对应的图层受影响(feature.mWindowLayers[layer]=true),并且之前没有PendingArea对象或者之前的PendingArea对象的父PendingArea和当前图层的PendingArea对象不同,会新建一个该特色模式的PendingArea对象,使它的父PendingArea指向当前图层的PendingArea对象,并且将新创建的对象添加到当前图层的PendingArea对象的mChildren里,接着将当前图层的PendingArea对象变成新生成的PendingArea对象。
  这两层循环执行完毕之后,PendingArea对象树形结构如下:
Android 窗口结构(一) 窗口层级构造_第2张图片

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

  这段代码是为窗口图层每层添加叶子PendingArea对象,每层叶子节点对象对应的类型分为三种:LEAF_TYPE_TOKENS、LEAF_TYPE_TASK_CONTAINERS、LEAF_TYPE_IME_CONTAINERS。第2层,也就是APPLICATION_LAYER层,为LEAF_TYPE_TASK_CONTAINERS;第15、16层,也就是TYPE_INPUT_METHOD、TYPE_INPUT_METHOD_DIALOG窗口类型对应的图层,为LEAF_TYPE_IME_CONTAINERS;其他的图层对应的类型为LEAF_TYPE_TOKENS。
  在叶子对象为null、或者叶子对象的父PendingArea和当前图层的PendingArea对象不同、或者叶子节点不同于上次叶子的类型的时候,都会创建新的叶子对象。
  叶子对象和正常的不同的是它的feature为null,叶子对象也会加入到当前图层的PendingArea对象的孩子节点中。
  并且在叶子对应的图层类型为LEAF_TYPE_TASK_CONTAINERS、LEAF_TYPE_IME_CONTAINERS时,会进行特殊处理。
  在为LEAF_TYPE_IME_CONTAINERS时,直接将叶子的mExisting设置为mImeContainer。mImeContainer为DisplayContent对象的成员变量mImeWindowsContainer,它是ImeContainer对象,该类继承DisplayArea.Tokens。
  在为LEAF_TYPE_TASK_CONTAINERS时,会调用addTaskDisplayAreasToApplicationLayer(areaForLayer[layer])将HierarchyBuilder对象的mTaskDisplayAreas集合里的内容添加到当前图层的PendingArea对象的孩子中。

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

  可见也是将mTaskDisplayAreas中的对象设置为新创建PendingArea 对象的成员变量mExisting 。mTaskDisplayAreas中的对象,是我们前面说的默认TaskDisplayArea对象defaultTaskDisplayArea,最后将该 新创建PendingArea 对象添加到当前图层对应的PendingArea 对象的孩子中。
  经过这第三段的代码的循环之后,上面的PendingArea对象树形结构图就编程如下:
Android 窗口结构(一) 窗口层级构造_第3张图片

带叶子的PendingArea对象树形结构
  再接下来看看第四段代码:
// We built a tree of PendingAreas above with all the necessary info to represent the
            // hierarchy, now create and attach real DisplayAreas to the root.
            root.instantiateChildren(mRoot, displayAreaForLayer, 0, featureAreas);

  PendingArea对象树形结构构建完成,现在调用树根root的instantiateChildren()方法,来构建窗口层级图,其中mRoot是DisplayContent对象,displayAreaForLayer是每层的DisplayArea对象,featureAreas是每个特色模式里面所有的非叶子节点生成的DisplayArea对象,displayAreaForLayer和featureAreas里的值都是在方法中生成的,继续看PendingArea的instantiateChildren():

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

  首先会将孩子按照mMinLayer的值进行升序排列。然后调用孩子的createArea()生成DisplayArea对象。如果该节点生成的DisplayArea对象为null,就继续执行下一个孩子节点的循环操作。如果生成了DisplayArea对象,会将该对象加入到parent的孩子中的最上面,我们知道parent目前是DisplayContent对象。接着会判断孩子的mFeature对象不为null,就添加到参数areas中。我们知道,节点是叶子的时候,它的mFeature 才会为null。所以这个是筛掉叶子节点。接着就是递归调用孩子的instantiateChildren()。不过这次传入的parent参数,是孩子刚才生成的DisplayArea对象。
  继续看下createArea()方法:

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

  在这里,我们能看到PendingArea类的mExisting 和mSkipTokens属性的使用。如果mExisting 存在直接就返回它,不会重新生成新的。
  如果mExisting 不存在,并且mSkipTokens= true,这个时候,会返回null。
  如果mExisting 不存在,并且mSkipTokens= false,则会新生成DisplayArea对象。新生成的DisplayArea对象,如果mFeature 为null,则为DisplayArea.Tokens对象。不然,则会调用mFeature.mNewDisplayAreaSupplier的create()方法生成具体的对象。我们知道,在前面添加特色模式时,会将mFeature.mNewDisplayAreaSupplier设置为DisplayArea.Dimmable::new。如果不设置mFeature.mNewDisplayAreaSupplier,它默认为DisplayArea::new。
  我们还看到,新生成的DisplayArea对象的type,是根据PendingArea类的mMinLayer 和mMaxLayer 来决定。
  如果新生成的DisplayArea对象是Tokens 类型,会填充参数areaForLayer数组,将对应层级的Tokens对象放入其中。
  这第四段代码执行完毕,之后,窗口层级结构就完成了,如下
Android 窗口结构(一) 窗口层级构造_第4张图片

默认屏幕窗口结构
  图片上的小数字对应窗口图层,这样默认屏幕上的窗口层级结构基本构造完成。

  结合前面说的窗口层级结构的根对象,是RootWindowContainer对象。如果要补全多屏幕的窗口层级结构,还要分析其他屏幕的构造,不过是比默认屏幕少好几个特色模式的,要比默认屏幕的结构要简单一些。
  前面在提到RootWindowContainer的setWindowManager(WindowManagerService wm)方法时,是说屏幕构造函数完成之后,会创建HomeTask,创建HomeTask的内容,放到下一篇文章里面介绍。

你可能感兴趣的:(android)