前言
DisplayContent 用于管理屏幕,一块DisplayContent 对象实例代表一个屏幕设备,这样有多个屏幕的设备就可以创建多个DisplayContent 对象,虽然多数设备只有一个显示屏,但它们同样可以创建多个 DisplayContent 对象,如投屏的时候,可以创建一个虚拟的DisplayContent,DisplayContent会根据窗口的显示位置将窗口进行分组,隶属于同一个DisplayContent的窗口将会显示在同一个屏幕中,每一个DisplayContent都对应一个唯一的ID,在添加窗口时可以通过指定这个ID决定其将被显示在对应的个屏幕中。DisplayContent是一个非常具有隔离性的一个概念。处于不同DisplayContent的两个窗口在布局、显示顺序以及动画处理上不会产生任何耦合。因此,就这几个方面来说, DisplayContent就像一个孤岛,所有这些操作都可以在其内部独立执行,DisplayContent使得这些原本属于整个WMS全局性的操作,变成了DisplayContent内部的操作。
一、DisplayContent 的创建
1、DisplayContent对象实例的创建最早是在SystemServer中被触发的。
frameworks/base/services/java/com/android/server/SystemServer.java
public final class SystemServer implements Dumpable {
private ActivityManagerService mActivityManagerService;
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
...代码省略...
t.traceBegin("SetWindowManagerService");
mActivityManagerService.setWindowManager(wm);//创建屏幕设备对象
t.traceEnd();
...代码省略...
}
}
该方法会调用ActivityManagerService的setWindowManager方法。
2、ActivityManagerService的setWindowManager方法如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback, ActivityManagerGlobalLock {
public WindowManagerService mWindowManager;
public ActivityTaskManagerService mActivityTaskManager;
public void setWindowManager(WindowManagerService wm) {
synchronized (this) {
mWindowManager = wm;
mWmInternal = LocalServices.getService(WindowManagerInternal.class);
mActivityTaskManager.setWindowManager(wm);//创建屏幕设备对象
}
}
}
该方法会调用ActivityTaskManagerService的setWindowManager方法。
3、ActivityTaskManagerService的setWindowManager方法如下所示。
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
RootWindowContainer mRootWindowContainer;
public void setWindowManager(WindowManagerService wm) {
synchronized (mGlobalLock) {
mWindowManager = wm;
mRootWindowContainer = wm.mRoot;//获取WindowManagerService的RootWindowContainer对象
mWindowOrganizerController.setWindowManager(wm);
mTempConfig.setToDefaults();
mTempConfig.setLocales(LocaleList.getDefault());
mConfigurationSeq = mTempConfig.seq = 1;
mRootWindowContainer.onConfigurationChanged(mTempConfig);
mLockTaskController.setWindowManager(wm);
mTaskSupervisor.setWindowManager(wm);
mRootWindowContainer.setWindowManager(wm);//创建屏幕设备对象
}
}
}
该方法会继续调用RootWindowContainer的setWindowManager方法。
4、DisplayContent对象实例就是在RootWindowContainer的setWindowManager方法中创建的。
frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
class RootWindowContainer extends WindowContainer<DisplayContent>
implements DisplayManager.DisplayListener {
DisplayManager mDisplayManager;
/** Reference to default display so we can quickly look it up. */
private DisplayContent mDefaultDisplay;
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();//通过DisplayManager获取屏幕设备信息
for (int displayNdx = 0; displayNdx < displays.length; ++displayNdx) {//遍历屏幕设备,为每个设备创建DisplayContent对象
final Display display = displays[displayNdx];
final DisplayContent displayContent = new DisplayContent(display, this);//创建屏幕对象DisplayContent实例
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 */);
}
//添加新创建的DisplayContent屏幕设备对象,将其存储到父类属性mChildren集合中
void addChild(E child, int index) {
if (!child.mReparenting && child.getParent() != null) {
throw new IllegalArgumentException("addChild: container=" + child.getName()
+ " is already a child of container=" + child.getParent().getName()
+ " can't add to container=" + getName()
+ "\n callers=" + Debug.getCallers(15, "\n"));
}
if ((index < 0 && index != POSITION_BOTTOM)
|| (index > mChildren.size() && index != POSITION_TOP)) {
throw new IllegalArgumentException("addChild: invalid position=" + index
+ ", children number=" + mChildren.size());
}
if (index == POSITION_TOP) {
index = mChildren.size();
} else if (index == POSITION_BOTTOM) {
index = 0;
}
//将DisplayContent屏幕设备对象存储到父类属性mChildren集合中
mChildren.add(index, child);
// Set the parent after we've actually added a child in case a subclass depends on this.
child.setParent(this);
}
}
frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable {
protected final WindowList<E> mChildren = new WindowList<E>();
}
1)首先通过DisplayManager获取当前存在的屏幕设备信息数组,然后遍历该数组为每个屏幕设备创建对应的DisplayContent对象实例。
2)调用addChild方法依次将创建的DisplayContent对象实例存储到父类的mChildren集合中。
二、DisplayContent类定义
frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.DisplayContentInfo {
/**
* 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);
if (mWmService.mRoot.getDisplayContent(display.getDisplayId()) != null) {
throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
+ " already exists="
+ mWmService.mRoot.getDisplayContent(display.getDisplayId())
+ " new=" + display);
}
mRootWindowContainer = root;
mAtmService = mWmService.mAtmService;
mDisplay = display;
mDisplayId = display.getDisplayId();
mCurrentUniqueDisplayId = display.getUniqueId();
mOffTokenAcquirer = mRootWindowContainer.mDisplayOffTokenAcquirer;
mWallpaperController = new WallpaperController(mWmService, this);
display.getDisplayInfo(mDisplayInfo);
display.getMetrics(mDisplayMetrics);
mSystemGestureExclusionLimit = mWmService.mConstants.mSystemGestureExclusionLimitDp
* mDisplayMetrics.densityDpi / DENSITY_DEFAULT;
isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
mInsetsStateController = new InsetsStateController(this);
mDisplayFrames = new DisplayFrames(mDisplayId, mInsetsStateController.getRawInsetsState(),
mDisplayInfo, calculateDisplayCutoutForRotation(mDisplayInfo.rotation),
calculateRoundedCornersForRotation(mDisplayInfo.rotation),
calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation));
initializeDisplayBaseInfo();
mAppTransition = new AppTransition(mWmService.mContext, mWmService, this);
mAppTransition.registerListenerLocked(mWmService.mActivityManagerAppTransitionNotifier);
mAppTransition.registerListenerLocked(mFixedRotationTransitionListener);
mAppTransitionController = new AppTransitionController(mWmService, this);
mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this);
final InputChannel inputChannel = mWmService.mInputManager.monitorInput(
"PointerEventDispatcher" + mDisplayId, mDisplayId);
mPointerEventDispatcher = new PointerEventDispatcher(inputChannel, this);
// Tap Listeners are supported for:
// 1. All physical displays (multi-display).
// 2. VirtualDisplays on VR, AA (and everything else).
mTapDetector = new TaskTapPointerEventListener(mWmService, this);
registerPointerEventListener(mTapDetector);
registerPointerEventListener(mWmService.mMousePositionTracker);
if (mWmService.mAtmService.getRecentTasks() != null) {
registerPointerEventListener(
mWmService.mAtmService.getRecentTasks().getInputListener());
}
mDisplayPolicy = new DisplayPolicy(mWmService, this);
mDisplayRotation = new DisplayRotation(mWmService, this);
mCloseToSquareMaxAspectRatio = mWmService.mContext.getResources().getFloat(
com.android.internal.R.dimen.config_closeToSquareDisplayMaxAspectRatio);
if (isDefaultDisplay) {
// The policy may be invoked right after here, so it requires the necessary default
// fields of this display content.
mWmService.mPolicy.setDefaultDisplay(this);
}
if (mWmService.mDisplayReady) {
mDisplayPolicy.onConfigurationChanged();
}
if (mWmService.mSystemReady) {
mDisplayPolicy.systemReady();
}
mWindowCornerRadius = mDisplayPolicy.getWindowCornerRadius();
mDividerControllerLocked = new DockedTaskDividerController(this);
mPinnedTaskController = new PinnedTaskController(mWmService, this);
final Transaction pendingTransaction = getPendingTransaction();
configureSurfaces(pendingTransaction);
pendingTransaction.apply();
// Sets the display content for the children.
onDisplayChanged(this);
updateDisplayAreaOrganizers();
mInputMonitor = new InputMonitor(mWmService, this);
mInsetsPolicy = new InsetsPolicy(mInsetsStateController, this);
if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Creating display=" + display);
mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this);
}
}