WindowManagerService的addWindow方法用于添加窗口,代码如下:
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
int displayId, int requestUserId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls, Rect outAttachedFrame,
float[] outSizeCompatScale) {
Arrays.fill(outActiveControls, null);
int[] appOp = new int[1];
final boolean isRoundedCornerOverlay = (attrs.privateFlags
& PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;
int res = mPolicy.checkAddPermission(attrs.type, isRoundedCornerOverlay, attrs.packageName,
appOp);
if (res != ADD_OKAY) {
return res;
}
WindowState parentWindow = null;
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
final int type = attrs.type;
synchronized (mGlobalLock) {
if (!mDisplayReady) {
throw new IllegalStateException("Display has not been initialialized");
}
final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
if (displayContent == null) {
ProtoLog.w(WM_ERROR, "Attempted to add window to a display that does "
+ "not exist: %d. Aborting.", displayId);
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
if (!displayContent.hasAccess(session.mUid)) {
ProtoLog.w(WM_ERROR,
"Attempted to add window to a display for which the application "
+ "does not have access: %d. Aborting.",
displayContent.getDisplayId());
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
if (mWindowMap.containsKey(client.asBinder())) {
ProtoLog.w(WM_ERROR, "Window %s is already added", client);
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
parentWindow = windowForClientLocked(null, attrs.token, false);
if (parentWindow == null) {
ProtoLog.w(WM_ERROR, "Attempted to add window with token that is not a window: "
+ "%s. Aborting.", attrs.token);
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
&& parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
ProtoLog.w(WM_ERROR, "Attempted to add window with token that is a sub-window: "
+ "%s. Aborting.", attrs.token);
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
}
if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
ProtoLog.w(WM_ERROR,
"Attempted to add private presentation window to a non-private display. "
+ "Aborting.");
return WindowManagerGlobal.ADD_PERMISSION_DENIED;
}
if (type == TYPE_PRESENTATION && !displayContent.getDisplay().isPublicPresentation()) {
ProtoLog.w(WM_ERROR,
"Attempted to add presentation window to a non-suitable display. "
+ "Aborting.");
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
int userId = UserHandle.getUserId(session.mUid);
if (requestUserId != userId) {
try {
mAmInternal.handleIncomingUser(callingPid, callingUid, requestUserId,
false /*allowAll*/, ALLOW_NON_FULL, null, null);
} catch (Exception exp) {
ProtoLog.w(WM_ERROR, "Trying to add window with invalid user=%d",
requestUserId);
return WindowManagerGlobal.ADD_INVALID_USER;
}
// It's fine to use this userId
userId = requestUserId;
}
ActivityRecord activity = null;
final boolean hasParent = parentWindow != null;
// Use existing parent window token for child windows since they go in the same token
// as there parent window so we can apply the same policy on them.
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
// If this is a child window, we want to apply the same type checking rules as the
// parent window type.
final int rootType = hasParent ? parentWindow.mAttrs.type : type;
boolean addToastWindowRequiresToken = false;
final IBinder windowContextToken = attrs.mWindowContextToken;
if (token == null) {
if (!unprivilegedAppCanCreateTokenWith(parentWindow, callingUid, type,
rootType, attrs.token, attrs.packageName)) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (hasParent) {
// Use existing parent window token for child windows.
token = parentWindow.mToken;
} else if (mWindowContextListenerController.hasListener(windowContextToken)) {
// Respect the window context token if the user provided it.
final IBinder binder = attrs.token != null ? attrs.token : windowContextToken;
final Bundle options = mWindowContextListenerController
.getOptions(windowContextToken);
token = new WindowToken.Builder(this, binder, type)
.setDisplayContent(displayContent)
.setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
.setRoundedCornerOverlay(isRoundedCornerOverlay)
.setFromClientToken(true)
.setOptions(options)
.build();
} else {
final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
token = new WindowToken.Builder(this, binder, type)
.setDisplayContent(displayContent)
.setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
.setRoundedCornerOverlay(isRoundedCornerOverlay)
.build();
}
} else if (rootType >= FIRST_APPLICATION_WINDOW
&& rootType <= LAST_APPLICATION_WINDOW) {
activity = token.asActivityRecord();
if (activity == null) {
ProtoLog.w(WM_ERROR, "Attempted to add window with non-application token "
+ ".%s Aborting.", token);
return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
} else if (activity.getParent() == null) {
ProtoLog.w(WM_ERROR, "Attempted to add window with exiting application token "
+ ".%s Aborting.", token);
return WindowManagerGlobal.ADD_APP_EXITING;
} else if (type == TYPE_APPLICATION_STARTING) {
if (activity.mStartingWindow != null) {
ProtoLog.w(WM_ERROR, "Attempted to add starting window to "
+ "token with already existing starting window");
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
if (activity.mStartingData == null) {
ProtoLog.w(WM_ERROR, "Attempted to add starting window to "
+ "token but already cleaned");
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
}
} else if (rootType == TYPE_INPUT_METHOD) {
if (token.windowType != TYPE_INPUT_METHOD) {
ProtoLog.w(WM_ERROR, "Attempted to add input method window with bad token "
+ "%s. Aborting.", attrs.token);
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (rootType == TYPE_VOICE_INTERACTION) {
if (token.windowType != TYPE_VOICE_INTERACTION) {
ProtoLog.w(WM_ERROR, "Attempted to add voice interaction window with bad token "
+ "%s. Aborting.", attrs.token);
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (rootType == TYPE_WALLPAPER) {
if (token.windowType != TYPE_WALLPAPER) {
ProtoLog.w(WM_ERROR, "Attempted to add wallpaper window with bad token "
+ "%s. Aborting.", attrs.token);
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {
ProtoLog.w(WM_ERROR,
"Attempted to add Accessibility overlay window with bad token "
+ "%s. Aborting.", attrs.token);
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (type == TYPE_TOAST) {
// Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,
callingUid, parentWindow);
if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {
ProtoLog.w(WM_ERROR, "Attempted to add a toast window with bad token "
+ "%s. Aborting.", attrs.token);
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (type == TYPE_QS_DIALOG) {
if (token.windowType != TYPE_QS_DIALOG) {
ProtoLog.w(WM_ERROR, "Attempted to add QS dialog window with bad token "
+ "%s. Aborting.", attrs.token);
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (token.asActivityRecord() != null) {
ProtoLog.w(WM_ERROR, "Non-null activity for system window of rootType=%d",
rootType);
// It is not valid to use an app token with other system types; we will
// instead make a new token for it (as if null had been passed in for the token).
attrs.token = null;
token = new WindowToken.Builder(this, client.asBinder(), type)
.setDisplayContent(displayContent)
.setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
.build();
}
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], attrs, viewVisibility, session.mUid, userId,
session.mCanAddInternalSystemWindow);
if (win.mDeathRecipient == null) {
// Client has apparently died, so there is no reason to
// continue.
ProtoLog.w(WM_ERROR, "Adding window client %s"
+ " that is dead, aborting.", client.asBinder());
return WindowManagerGlobal.ADD_APP_EXITING;
}
if (win.getDisplayContent() == null) {
ProtoLog.w(WM_ERROR, "Adding window to Display that has been removed.");
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
displayPolicy.adjustWindowParamsLw(win, win.mAttrs);
attrs.flags = sanitizeFlagSlippery(attrs.flags, win.getName(), callingUid, callingPid);
attrs.inputFeatures = sanitizeSpyWindow(attrs.inputFeatures, win.getName(), callingUid,
callingPid);
win.setRequestedVisibilities(requestedVisibilities);
res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
if (res != ADD_OKAY) {
return res;
}
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
win.openInputChannel(outInputChannel);
}
// If adding a toast requires a token for this app we always schedule hiding
// toast windows to make sure they don't stick around longer then necessary.
// We hide instead of remove such windows as apps aren't prepared to handle
// windows being removed under them.
//
// If the app is older it can add toasts without a token and hence overlay
// other apps. To be maximally compatible with these apps we will hide the
// window after the toast timeout only if the focused window is from another
// UID, otherwise we allow unlimited duration. When a UID looses focus we
// schedule hiding all of its toast windows.
if (type == TYPE_TOAST) {
if (!displayContent.canAddToastWindowForUid(callingUid)) {
ProtoLog.w(WM_ERROR, "Adding more than one toast window for UID at a time.");
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
// Make sure this happens before we moved focus as one can make the
// toast focusable to force it not being hidden after the timeout.
// Focusable toasts are always timed out to prevent a focused app to
// show a focusable toasts while it has focus which will be kept on
// the screen after the activity goes away.
if (addToastWindowRequiresToken
|| (attrs.flags & FLAG_NOT_FOCUSABLE) == 0
|| displayContent.mCurrentFocus == null
|| displayContent.mCurrentFocus.mOwnerUid != callingUid) {
mH.sendMessageDelayed(
mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),
win.mAttrs.hideTimeoutMilliseconds);
}
}
// Switch to listen to the {@link WindowToken token}'s configuration changes when
// adding a window to the window context. Filter sub window type here because the sub
// window must be attached to the parent window, which is attached to the window context
// created window token.
if (!win.isChildWindow()
&& mWindowContextListenerController.hasListener(windowContextToken)) {
final int windowContextType = mWindowContextListenerController
.getWindowType(windowContextToken);
final Bundle options = mWindowContextListenerController
.getOptions(windowContextToken);
if (type != windowContextType) {
ProtoLog.w(WM_ERROR, "Window types in WindowContext and"
+ " LayoutParams.type should match! Type from LayoutParams is %d,"
+ " but type from WindowContext is %d", type, windowContextType);
// We allow WindowProviderService to add window other than windowContextType,
// but the WindowProviderService won't be associated with the window's
// WindowToken.
if (!isWindowProviderService(options)) {
return WindowManagerGlobal.ADD_INVALID_TYPE;
}
} else {
mWindowContextListenerController.registerWindowContainerListener(
windowContextToken, token, callingUid, type, options);
}
}
// From now on, no exceptions or errors allowed!
res = ADD_OKAY;
if (mUseBLAST) {
res |= WindowManagerGlobal.ADD_FLAG_USE_BLAST;
}
if (displayContent.mCurrentFocus == null) {
displayContent.mWinAddedSinceNullFocus.add(win);
}
if (excludeWindowTypeFromTapOutTask(type)) {
displayContent.mTapExcludedWindows.add(win);
}
win.attach();
mWindowMap.put(client.asBinder(), win);
win.initAppOpsState();
final boolean suspended = mPmInternal.isPackageSuspended(win.getOwningPackage(),
UserHandle.getUserId(win.getOwningUid()));
win.setHiddenWhileSuspended(suspended);
final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty();
win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);
boolean imMayMove = true;
win.mToken.addWindow(win);
displayPolicy.addWindowLw(win, attrs);
displayPolicy.setDropInputModePolicy(win, win.mAttrs);
if (type == TYPE_APPLICATION_STARTING && activity != null) {
activity.attachStartingWindow(win);
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s",
activity, win);
} else if (type == TYPE_INPUT_METHOD
// IME window is always touchable.
// Ignore non-touchable windows e.g. Stylus InkWindow.java.
&& (win.getAttrs().flags & FLAG_NOT_TOUCHABLE) == 0) {
displayContent.setInputMethodWindowLocked(win);
imMayMove = false;
} else if (type == TYPE_INPUT_METHOD_DIALOG) {
displayContent.computeImeTarget(true /* updateImeTarget */);
imMayMove = false;
} else {
if (type == TYPE_WALLPAPER) {
displayContent.mWallpaperController.clearLastWallpaperTimeoutTime();
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
} else if (win.hasWallpaper()) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
} else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) {
// If there is currently a wallpaper being shown, and
// the base layer of the new window is below the current
// layer of the target window, then adjust the wallpaper.
// This is to avoid a new window being placed between the
// wallpaper and its target.
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
}
final WindowStateAnimator winAnimator = win.mWinAnimator;
winAnimator.mEnterAnimationPending = true;
winAnimator.mEnteringAnimation = true;
// Check if we need to prepare a transition for replacing window first.
if (!win.mTransitionController.isShellTransitionsEnabled()
&& activity != null && activity.isVisible()
&& !prepareWindowReplacementTransition(activity)) {
// If not, check if need to set up a dummy transition during display freeze
// so that the unfreeze wait for the apps to draw. This might be needed if
// the app is relaunching.
prepareNoneTransitionForRelaunching(activity);
}
if (displayPolicy.areSystemBarsForcedConsumedLw()) {
res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS;
}
if (mInTouchMode) {
res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
}
if (win.mActivityRecord == null || win.mActivityRecord.isClientVisible()) {
res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
}
displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
boolean focusChanged = false;
if (win.canReceiveKeys()) {
focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
false /*updateInputWindows*/);
if (focusChanged) {
imMayMove = false;
}
}
if (imMayMove) {
displayContent.computeImeTarget(true /* updateImeTarget */);
}
// Don't do layout here, the window must call
// relayout to be displayed, so we'll do it there.
win.getParent().assignChildLayers();
if (focusChanged) {
displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus,
false /*updateInputWindows*/);
}
displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s"
+ ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5));
boolean needToSendNewConfiguration =
win.isVisibleRequestedOrAdding() && displayContent.updateOrientation();
if (win.providesNonDecorInsets()) {
needToSendNewConfiguration |= displayPolicy.updateDecorInsetsInfo();
}
if (needToSendNewConfiguration) {
displayContent.sendNewConfiguration();
}
// This window doesn't have a frame yet. Don't let this window cause the insets change.
displayContent.getInsetsStateController().updateAboveInsetsState(
false /* notifyInsetsChanged */);
outInsetsState.set(win.getCompatInsetsState(), true /* copySources */);
getInsetsSourceControls(win, outActiveControls);
if (win.mLayoutAttached) {
outAttachedFrame.set(win.getParentWindow().getFrame());
if (win.mInvGlobalScale != 1f) {
outAttachedFrame.scale(win.mInvGlobalScale);
}
} else {
// Make this invalid which indicates a null attached frame.
outAttachedFrame.set(0, 0, -1, -1);
}
outSizeCompatScale[0] = win.getCompatScaleForClient();
}
Binder.restoreCallingIdentity(origId);
return res;
}
}
上面方法主要处理如下:
1、通过WindowToken的构造器创建WindowToken对象。
2、通过new的方法创建WindowState对象。
3、调用win(WindowState)的attach方法。
4、调用win(WindowState)的成员变量mToken(WindowToken)的addWindow(win)方法,将WindowState加入到WindowToken中。
下面分别进行分析:
WindowToken Builder build
通过WindowToken的构造器创建WindowToken对象:
//frameworks/base/service/java/com/android/server/wm/WindowToken.java
class WindowToken extends WindowContainer<WindowState> {
static class Builder {
WindowToken build() {
return new WindowToken(mService, mToken, mType, mPersistOnEmpty, mDisplayContent,
mOwnerCanManageAppTokens, mRoundedCornerOverlay, mFromClientToken, mOptions);
}
}
}
通过new的方式创建WindowToken对象,WindowToken的构造方法如下:
//frameworks/base/service/java/com/android/server/wm/WindowToken.java
class WindowToken extends WindowContainer<WindowState>{}
protected WindowToken(WindowManagerService service, IBinder _token, int type,
boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens,
boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) {
super(service);
token = _token;
windowType = type;
mOptions = options;
mPersistOnEmpty = persistOnEmpty;
mOwnerCanManageAppTokens = ownerCanManageAppTokens;
mRoundedCornerOverlay = roundedCornerOverlay;
mFromClientToken = fromClientToken;
if (dc != null) {
dc.addWindowToken(token, this);
}
}
}
new WindowState
通过new的方法创建WindowState对象,WindowState的构造方法如下:
//frameworks/base/service/java/com/android/server/wm/WindowState.java
class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState,
InsetsControlTarget, InputTarget {
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow) {
this(service, s, c, token, parentWindow, appOp, a, viewVisibility, ownerId, showUserId,
ownerCanAddInternalSystemWindow, new PowerManagerWrapper() {
@Override
public void wakeUp(long time, @WakeReason int reason, String details) {
service.mPowerManager.wakeUp(time, reason, details);
}
@Override
public boolean isInteractive() {
return service.mPowerManager.isInteractive();
}
});
}
}
WindowState attach
调用win(WindowState)的attach方法:
//frameworks/base/service/java/com/android/server/wm/WindowState.java
class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState,
InsetsControlTarget, InputTarget {
final Session mSession; // 创建ViewRootImpl时创建,并传给WMS, 在new WindowState时初始化
void attach() {
if (DEBUG) Slog.v(TAG, "Attaching " + this + " token=" + mToken);
mSession.windowAddedLocked();
}
}
调用mSession(Session)的windowAddedLocked方法:
//frameworks/base/service/java/com/android/server/wm/Session.java
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
SurfaceSession mSurfaceSession;
void windowAddedLocked() {
if (mPackageName == null) {
final WindowProcessController wpc = mService.mAtmService.mProcessMap.getProcess(mPid);
if (wpc != null) {
mPackageName = wpc.mInfo.packageName;
mRelayoutTag = "relayoutWindow: " + mPackageName;
} else {
Slog.e(TAG_WM, "Unknown process pid=" + mPid);
}
}
if (mSurfaceSession == null) {
if (DEBUG) {
Slog.v(TAG_WM, "First window added to " + this + ", creating SurfaceSession");
}
mSurfaceSession = new SurfaceSession(); // 创建 SurfaceSession
ProtoLog.i(WM_SHOW_TRANSACTIONS, " NEW SURFACE SESSION %s", mSurfaceSession);
mService.mSessions.add(this);
if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
mService.dispatchNewAnimatorScaleLocked(this);
}
}
mNumWindow++;
}
}
new SurfaceSession
通过new的方式创建SurfaceSession对象,SurfaceSession是Android系统中与图形表面相关的一个关键类,它提供了与SurfaceFlinger服务通信以创建和管理图形表面连接的API,SurfaceSession在WindowManagerService的addWindow时创建,构造方法如下:
//frameworks/base/core/java/android/view/SurfaceSession.java
public final class SurfaceSession {
public SurfaceSession() {
mNativeClient = nativeCreate();
}
}
调用nativeCreate方法,nativeCreate是个Native方法,通过查表调用android_view_SurfaceSession.cpp的nativeCreate方法:
//frameworks/base/core/jni/android_view_SurfaceSession.cpp
static jlong nativeCreate(JNIEnv* env, jclass clazz) {
SurfaceComposerClient* client = new SurfaceComposerClient(); //创建SurfaceComposerClient对象
client->incStrong((void*)nativeCreate);
return reinterpret_cast<jlong>(client);
}
通过new的方式创建SurfaceComposerClient对象,SurfaceComposerClient的构造方法如下:
//frameworks/native/libs/gui/SurfaceComposerClient.cpp
class SurfaceComposerClient : public RefBase
SurfaceComposerClient::SurfaceComposerClient() : mStatus(NO_INIT) {}
}
WindowToken addWindow
调用win(WindowState)的成员变量mToken(WindowToken)的addWindow(win)方法,将WindowState加入到WindowToken中:
//frameworks/base/service/java/com/android/server/wm/WindowToken.java
class WindowToken extends WindowContainer<WindowState> {
void addWindow(final WindowState win) {
ProtoLog.d(WM_DEBUG_FOCUS,
"addWindow: win=%s Callers=%s", win, Debug.getCallers(5));
if (win.isChildWindow()) {
// Child windows are added to their parent windows.
return;
}
// This token is created from WindowContext and the client requests to addView now, create a
// surface for this token.
if (mSurfaceControl == null) {
createSurfaceControl(true /* force */);
// Layers could have been assigned before the surface was created, update them again
reassignLayer(getSyncTransaction());
}
if (!mChildren.contains(win)) {
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", win, this);
addChild(win, mWindowComparator);
mWmService.mWindowsChanged = true;
// TODO: Should we also be setting layout needed here and other places?
}
}
}