WindowContainer
WindowContainer用于作为一个Window容器,用于管理添加进来的子WindowContainer。在WMS中存在以下几种WIndowContainer:
WindowContainer作为这些Container的父类,主要提供对child container的添加操作:
protected void addChild(E child, Comparator<E> comparator) {
if (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());
}
int positionToAdd = -1;
if (comparator != null) {
final int count = mChildren.size();
for (int i = 0; i < count; i++) {
if (comparator.compare(child, mChildren.get(i)) < 0) {
positionToAdd = i;
break;
}
}
}
if (positionToAdd == -1) {
mChildren.add(child);
} else {
mChildren.add(positionToAdd, child);
}
onChildAdded(child);
// Set the parent after we've actually added a child in case a subclass depends on this.
child.setParent(this);
}
addChild根据该container的comparator比较mChildren中的child,找到指定插入位置,可以使得mChildren中的E按照一定顺序排列,并且child能够直接找到其父container.
1、DisplayContent
其对应于一个显示屏的容器,但是其不可能存在子屏,所以其不能直接addChild。 具体参见android wms——DisplayContent中内容。
2、WindowState
用于控制每一个window的状态,包含计算当前窗体的大小,以及session的绑定。其添加child是按照mSubLayer 子序排序。
3、WindowToken
作为window句柄,其子成员为WindowState,只核心变量成员IBinder token对应于APP端的Window。其子成员windowState的添加策略是根据该windowState.mBaseLayer 主序(也就是window的类型)从小到大排序。具体参见android WMS—— WindowToken。
4、Task
Activity对应的栈,其子container为AppWindowToken,因此实际上为控制APP端Activity对应的AppWindowToken的List集合。其成员变量中包含mTaskId。
5、TaskStack
子Container为task,其实际为WMS中管理task的数据结构。
WindowContainerControl
class WindowContainerController<E extends WindowContainer, I extends WindowContainerListener>
implements ConfigurationContainerListener {
final WindowManagerService mService;
final RootWindowContainer mRoot;
final WindowHashMap mWindowMap;
// The window container this controller owns.
E mContainer;
// Interface for communicating changes back to the owner.
final I mListener;
WindowContainerController(I listener, WindowManagerService service) {
mListener = listener;
mService = service;
mRoot = mService != null ? mService.mRoot : null;
mWindowMap = mService != null ? mService.mWindowMap : null;
}
void setContainer(E container) {
if (mContainer != null && container != null) {
throw new IllegalArgumentException("Can't set container=" + container
+ " for controller=" + this + " Already set to=" + mContainer);
}
mContainer = container;
if (mContainer != null && mListener != null) {
mListener.registerConfigurationChangeListener(this);
}
}
......
}
该Control会传入WMS,并获得其WMS中的RootWindowContainer和WindowHashMap。通过SetContainer控制一个WindowContainer,并监听该WindowConatainer回调的onOverrideConfigurationChanged
1、AppWindowContainerController
public class AppWindowContainerController
extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
......
public AppWindowContainerController(TaskWindowContainerController taskController,
IApplicationToken token, AppWindowContainerListener listener, int index,
int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
WindowManagerService service) {
super(listener, service);
mHandler = new H(service.mH.getLooper());
mToken = token;
synchronized(mWindowMap) {
AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
if (atoken != null) {
// TODO: Should this throw an exception instead?
Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
return;
}
final Task task = taskController.mContainer;
if (task == null) {
throw new IllegalArgumentException("AppWindowContainerController: invalid "
+ " controller=" + taskController);
}
atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
alwaysFocusable, this);
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
+ " controller=" + taskController + " at " + index);
task.addChild(atoken, index);
}
}
......
}
其作用是监听的AppWindowToken中回调AppWindowContainerListener。
其被创建的地方在ActivityRecord.createWindowContainer函数中,从其构造函数中可以看出,其通过查找WMS.mRoot中查找IApplicationToken对应的AppWindowToken,如果没有找到,则需要生成一个新的AppWindowToken,并把其添加到task中。
2、TaskWindowContainerController
public class TaskWindowContainerController
extends WindowContainerController<Task, TaskWindowContainerListener> {
......
public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener,
StackWindowController stackController, int userId, Rect bounds, int resizeMode,
boolean supportsPictureInPicture, boolean toTop, boolean showForAllUsers,
TaskDescription taskDescription, WindowManagerService service) {
super(listener, service);
mTaskId = taskId;
mHandler = new H(new WeakReference<>(this), service.mH.getLooper());
synchronized(mWindowMap) {
if (DEBUG_STACK) Slog.i(TAG_WM, "TaskWindowContainerController: taskId=" + taskId
+ " stack=" + stackController + " bounds=" + bounds);
final TaskStack stack = stackController.mContainer;
if (stack == null) {
throw new IllegalArgumentException("TaskWindowContainerController: invalid stack="
+ stackController);
}
EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId);
final Task task = createTask(taskId, stack, userId, resizeMode,
supportsPictureInPicture, taskDescription);
final int position = toTop ? POSITION_TOP : POSITION_BOTTOM;
// We only want to move the parents to the parents if we are creating this task at the
// top of its stack.
stack.addTask(task, position, showForAllUsers, toTop /* moveParents */);
}
}
......
}
其监听的是task的回调,在系统中通过 ActivityStack.createTaskRecord在生成TaskRecord后调用TaskRecord.createWindowContainer创建该control。其同样会被添加到TaskStack中
3、StackWindowController
public class StackWindowController
extends WindowContainerController<TaskStack, StackWindowListener> {
.....
public StackWindowController(int stackId, StackWindowListener listener,
int displayId, boolean onTop, Rect outBounds, WindowManagerService service) {
super(listener, service);
mStackId = stackId;
mHandler = new H(new WeakReference<>(this), service.mH.getLooper());
synchronized (mWindowMap) {
final DisplayContent dc = mRoot.getDisplayContent(displayId);
if (dc == null) {
throw new IllegalArgumentException("Trying to add stackId=" + stackId
+ " to unknown displayId=" + displayId);
}
dc.createStack(stackId, onTop, this);
getRawBounds(outBounds);
}
}
.....
}
其监听的是TaskStack的回调,从构造函数可以看出其直接通过DisplayContent.createStack生成。其相对于其他几个control应该属于比较顶层,直接面对DisplayContent。
TaskStack createStack(int stackId, boolean onTop, StackWindowController controller) {
if (DEBUG_STACK) Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId="
+ mDisplayId);
final TaskStack stack = new TaskStack(mService, stackId, controller);
mTaskStackContainers.addStackToDisplay(stack, onTop);
return stack;
}
从函数中看,其创建的TaskStack添加到的是DisplayContent.mTaskStackContainers应用Container中,该mTaskStackContainers控制着当前逻辑屏幕主要的Stack,如Home,分屏等。
其创建是在ActivityDisplay.createStackUnchecked中通过创建ActivityStack的时候,在ActivityStack构造函数中生成该control的
4、DisplayWindowController
public class DisplayWindowController
extends WindowContainerController<DisplayContent, WindowContainerListener> {
public DisplayWindowController(Display display, WindowContainerListener listener) {
super(listener, WindowManagerService.getInstance());
mDisplayId = display.getDisplayId();
synchronized (mWindowMap) {
final long callingIdentity = Binder.clearCallingIdentity();
try {
mRoot.createDisplayContent(display, this /* controller */);
} finally {
Binder.restoreCallingIdentity(callingIdentity);
}
if (mContainer == null) {
throw new IllegalArgumentException("Trying to add display=" + display
+ " dc=" + mRoot.getDisplayContent(mDisplayId));
}
}
}
}
其对应监听的是DisplayContent的回调函数,其通过 RootWindowContainer.createDisplayContent在没有该display 情况下创建并加入到WMS.mRoot中。其在ActivityDisplay构造函数中调用创建mWindowContainerController。
总结
根据上面对应关系,可以发现WMS中的Container与ContainerControl相对应,而ContainerControl都是在通过AMS部分启动,从其创建看出其相对应存在着关系:
因为每个WindowContainerController与WindowContainer是一一对应关系,所以在使用中可以直接通过WindowContainerController.mContainer直接找到对应的Container。