前言
上文说到调用了WMS中的addWindow来添加窗口
其中各参数意义参考:
session: 即为Client端ViewRootImpl持有的mWindowSession。 这个mWindowSession为WindowManagerGlobal创建,针对当前App而不是单个activity的WMS的代理。
client: 为ViewRootImpl持有的mWindow, 也就是WMS向activity发送消息的aidl接口。同时在WMS端也起到索引窗口的作用。
attrs:为该窗口的layout属性设置。
viewVisibility:是否可见,对于刚加入的activity window, 一般都是invisible的。 frameworks/base/core/java/android/view/View.java中定义
displayId:显示在哪个屏幕上
outContentInsets:看名字,前面有个out, 代表是由WMS返回给activity的参数,说明窗口内容区域边衬大小。如图所示:
outStableInsets: 算上status bar 或者navigation bar 的边衬区域。通常fullscreen的界面会用到这个值。
outOutsets: chin跟content 区域的offset, 所谓的chin, 比如,某个区域并不实际显示在屏幕上,但是希望它像显示在屏幕上一样。一般情况下,只都为0。可以在系统的resource中设置该区域的值。Resource为config_windowOutsetBottom。
outInputChannel:在WMS中建立一对inputChannel, 这两个inputChannel,监听管道的消息,但是方向相反,一个用于input manager service 转送消息给activity, 并接受来自activity的消息。 另一个用于activity发送消息给inputManagerservice, 并监听input manager service发送的消息,这个会传送回activity
WMS addWindow的相关逻辑
WindowManagerService#addWindow
构造system_server端对应的WindowState
创造对应的WindowState
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow,
PowerManagerWrapper powerManagerWrapper) {
super(service);
mSession = s;
mClient = c; //mClient可以用来回调客户端的ViewRootImpl
mAppOp = appOp;
mToken = token;
mAppToken = mToken.asAppWindowToken();
mOwnerUid = ownerId;
mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;
mWindowId = new WindowId(this);
mAttrs.copyFrom(a);
mLastSurfaceInsets.set(mAttrs.surfaceInsets);
mViewVisibility = viewVisibility;
mPolicy = mService.mPolicy;
mContext = mService.mContext;
DeathRecipient deathRecipient = new DeathRecipient();
mSeq = seq;
mEnforceSizeCompat = (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0;
mPowerManagerWrapper = powerManagerWrapper;
if (localLOGV) Slog.v(
TAG, "Window " + this + " client=" + c.asBinder()
+ " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
try {
c.asBinder().linkToDeath(deathRecipient, 0); //为mClient注册死亡回调
} catch (RemoteException e) {
mDeathRecipient = null;
mIsChildWindow = false;
mLayoutAttached = false;
mIsImWindow = false;
mIsWallpaper = false;
mIsFloatingLayer = false;
mBaseLayer = 0;
mSubLayer = 0;
mInputWindowHandle = null;
mWinAnimator = null;
return;
}
mDeathRecipient = deathRecipient;
if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
mIsChildWindow = true;
if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + parentWindow);
parentWindow.addChild(this, sWindowSubLayerComparator);
mLayoutAttached = mAttrs.type !=
WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
mIsImWindow = parentWindow.mAttrs.type == TYPE_INPUT_METHOD
|| parentWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
mIsWallpaper = parentWindow.mAttrs.type == TYPE_WALLPAPER;
} else {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
mBaseLayer = mPolicy.getWindowLayerLw(this)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
mSubLayer = 0;
mIsChildWindow = false;
mLayoutAttached = false;
mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
|| mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
}
mIsFloatingLayer = mIsImWindow || mIsWallpaper;
if (mAppToken != null && mAppToken.mShowForAllUsers) {
// Windows for apps that can show for all users should also show when the device is
// locked.
mAttrs.flags |= FLAG_SHOW_WHEN_LOCKED;
}
mWinAnimator = new WindowStateAnimator(this);
//每个WindowState有一个WindowStateAnimator,用于管理surface和动画相关
mWinAnimator.mAlpha = a.alpha;
mRequestedWidth = 0;
mRequestedHeight = 0;
mLastRequestedWidth = 0;
mLastRequestedHeight = 0;
mLayer = 0;
mInputWindowHandle = new InputWindowHandle(
mAppToken != null ? mAppToken.mInputApplicationHandle : null, this, c,
getDisplayId());
}
注册的客户端ViewRootImpl的死亡回调
private class DeathRecipient implements IBinder.DeathRecipient {
@Override
public void binderDied() {
try {
boolean resetSplitScreenResizing = false;
synchronized(mService.mWindowMap) {
final WindowState win = mService.windowForClientLocked(mSession, mClient, false);
Slog.i(TAG, "WIN DEATH: " + win); //打印WIN DEATH
if (win != null) {
final DisplayContent dc = getDisplayContent();
if (win.mAppToken != null && win.mAppToken.findMainWindow() == win) {
mService.mTaskSnapshotController.onAppDied(win.mAppToken);
}
win.removeIfPossible(shouldKeepVisibleDeadAppWindow());
if (win.mAttrs.type == TYPE_DOCK_DIVIDER) {
// The owner of the docked divider died :( We reset the docked stack,
// just in case they have the divider at an unstable position. Better
// also reset drag resizing state, because the owner can't do it
// anymore.
final TaskStack stack =
dc.getSplitScreenPrimaryStackIgnoringVisibility();
if (stack != null) {
stack.resetDockedStackToMiddle();
}
resetSplitScreenResizing = true;
}
} else if (mHasSurface) {
Slog.e(TAG, "!!! LEAK !!! Window removed but surface still valid.");
WindowState.this.removeIfPossible();
}
}
if (resetSplitScreenResizing) {
try {
// Note: this calls into ActivityManager, so we must *not* hold the window
// manager lock while calling this.
mService.mActivityManager.setSplitScreenResizing(false);
} catch (RemoteException e) {
// Local call, shouldn't return RemoteException.
throw e.rethrowAsRuntimeException();
}
}
} catch (IllegalArgumentException ex) {
// This will happen if the window has already been removed.
}
}
}
PhoneWindowManager#adjustWindowParamsLw
调整window的相关参数
@Override
public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
boolean hasStatusBarServicePermission) {
final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
if (mScreenDecorWindows.contains(win)) {
if (!isScreenDecor) {
// No longer has the flag set, so remove from the set.
mScreenDecorWindows.remove(win);
}
} else if (isScreenDecor && hasStatusBarServicePermission) {
mScreenDecorWindows.add(win);
}
switch (attrs.type) {
case TYPE_SYSTEM_OVERLAY:
case TYPE_SECURE_SYSTEM_OVERLAY:
// These types of windows can't receive input events.
attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
break;
case TYPE_DREAM:
case TYPE_WALLPAPER:
// Dreams and wallpapers don't have an app window token and can thus not be
// letterboxed. Hence always let them extend under the cutout.
attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
break;
case TYPE_STATUS_BAR:
// If the Keyguard is in a hidden state (occluded by another window), we force to
// remove the wallpaper and keyguard flag so that any change in-flight after setting
// the keyguard as occluded wouldn't set these flags again.
// See {@link #processKeyguardSetHiddenResultLw}.
if (mKeyguardOccluded) {
attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
}
break;
case TYPE_SCREENSHOT:
attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
break;
case TYPE_TOAST:
// While apps should use the dedicated toast APIs to add such windows
// it possible legacy apps to add the window directly. Therefore, we
// make windows added directly by the app behave as a toast as much
// as possible in terms of timeout and animation.
if (attrs.hideTimeoutMilliseconds < 0
|| attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
}
attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
break;
}
if (attrs.type != TYPE_STATUS_BAR) { //只有status bar类型的窗口可以在锁屏上展示?
// The status bar is the only window allowed to exhibit keyguard behavior.
attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
}
}
PhoneWindowManager#prepareAddWindowLw
做add window to system前的准备检查工作
/**
* Preflight adding a window to the system.
*
* Currently enforces that three window types are singletons:
*
* - STATUS_BAR_TYPE
* - KEYGUARD_TYPE
*
*
* @param win The window to be added
* @param attrs Information about the window to be added
*
* @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons,
* WindowManagerImpl.ADD_MULTIPLE_SINGLETON
*/
@Override
public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.STATUS_BAR_SERVICE,
"PhoneWindowManager");
mScreenDecorWindows.add(win);
}
switch (attrs.type) {
case TYPE_STATUS_BAR:
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.STATUS_BAR_SERVICE,
"PhoneWindowManager");
if (mStatusBar != null) {
if (mStatusBar.isAlive()) {
return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
}
}
mStatusBar = win;
mStatusBarController.setWindow(win);
setKeyguardOccludedLw(mKeyguardOccluded, true /* force */);
break;
case TYPE_NAVIGATION_BAR:
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.STATUS_BAR_SERVICE,
"PhoneWindowManager");
if (mNavigationBar != null) {
if (mNavigationBar.isAlive()) {
return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
}
}
mNavigationBar = win;
mNavigationBarController.setWindow(win);
mNavigationBarController.setOnBarVisibilityChangedListener(
mNavBarVisibilityListener, true);
if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
break;
case TYPE_NAVIGATION_BAR_PANEL:
case TYPE_STATUS_BAR_PANEL:
case TYPE_STATUS_BAR_SUB_PANEL:
case TYPE_VOICE_INTERACTION_STARTING:
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.STATUS_BAR_SERVICE,
"PhoneWindowManager");
break;
}
return ADD_OKAY; //准备完成后返回ADD_OKAY
}
WindowState#attach
void attach() {
if (localLOGV) Slog.v(TAG, "Attaching " + this + " token=" + mToken);
mSession.windowAddedLocked(mAttrs.packageName);
}
Session#windowAddedLocked
那么看起来每个应用进程对应一个Session,也对应一个mSurfaceSession
void windowAddedLocked(String packageName) {
mPackageName = packageName;
mRelayoutTag = "relayoutWindow: " + mPackageName; //属性赋值
if (mSurfaceSession == null) {
if (WindowManagerService.localLOGV) Slog.v(
TAG_WM, "First window added to " + this + ", creating SurfaceSession");
mSurfaceSession = new SurfaceSession();
if (SHOW_TRANSACTIONS) Slog.i(
TAG_WM, " NEW SURFACE SESSION " + mSurfaceSession);
mService.mSessions.add(this); //WMS中的mSessions保存所有的Session
if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
mService.dispatchNewAnimatorScaleLocked(this);
}
}
mNumWindow++;//Session中的窗口数量+1
}
然后win.mToken.addWindow(win);调用AppWindowToken.addWindow(WindowState) ,针对WindowToken形成一个WindowList List
AppWindowToken#addWindow
@Override
void addWindow(WindowState w) {
super.addWindow(w);
boolean gotReplacementWindow = false;
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState candidate = mChildren.get(i);
gotReplacementWindow |= candidate.setReplacementWindowIfNeeded(w);
}
// if we got a replacement window, reset the timeout to give drawing more time
if (gotReplacementWindow) {
mService.scheduleWindowReplacementTimeouts(this);
}
checkKeyguardFlagsChanged();
}
WindowToken#addWindow
void addWindow(final WindowState win) {
if (DEBUG_FOCUS) Slog.d(TAG_WM,
"addWindow: win=" + win + " Callers=" + Debug.getCallers(5));
if (win.isChildWindow()) {
// Child windows are added to their parent windows. //子窗口,WindowToken的mChildren不添加,直接return;而是会添加到父窗口WindowState的mChildren属性中
return;
}
if (!mChildren.contains(win)) {
if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
addChild(win, mWindowComparator); //调用WindowContainer的addChild
mService.mWindowsChanged = true;
// TODO: Should we also be setting layout needed here and other places?
}
}
注意WindowToken和WindowState均继承WindowContainer
43/**
44 * Container of a set of related windows in the window manager. Often this is an AppWindowToken,
45 * which is the handle for an Activity that it uses to display windows. For nested windows, there is
46 * a WindowToken created for the parent window to manage its children.
47 */
48class WindowToken extends WindowContainer {
class WindowState extends WindowContainer implements WindowManagerPolicy.WindowState
WindowContainer#addChild
/**
* Adds the input window container has a child of this container in order based on the input
* comparator.
* @param child The window container to add as a child of this window container.
* @param comparator Comparator to use in determining the position the child should be added to.
* If null, the child will be added to the top.
*/
@CallSuper
protected void addChild(E child, Comparator 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) {
//通过传入的comparator对mChildren进行排序
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); //为WindowState的mParent赋值 (那么一般来说WindowState.getParent()的mParent都是自己,对子窗口来说mParent为其父窗口)
}
// 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 mChildren = new WindowList();
WindowManagerService#updateFocusedWindowLocked
调整窗口的focus,在WMS中的addView中会调用
// TODO: Move to DisplayContent
boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
WindowState newFocus = mRoot.computeFocusedWindow();
if (mCurrentFocus != newFocus) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
// This check makes sure that we don't already have the focus
// change message pending.
mH.removeMessages(H.REPORT_FOCUS_CHANGE);
mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
// TODO(multidisplay): Focused windows on default display only.
final DisplayContent displayContent = getDefaultDisplayContentLocked();
boolean imWindowChanged = false;
if (mInputMethodWindow != null) {
final WindowState prevTarget = mInputMethodTarget;
final WindowState newTarget =
displayContent.computeImeTarget(true /* updateImeTarget*/);
imWindowChanged = prevTarget != newTarget;
if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS
&& mode != UPDATE_FOCUS_WILL_PLACE_SURFACES) {
final int prevImeAnimLayer = mInputMethodWindow.mWinAnimator.mAnimLayer;
displayContent.assignWindowLayers(false /* setLayoutNeeded */);
imWindowChanged |=
prevImeAnimLayer != mInputMethodWindow.mWinAnimator.mAnimLayer;
}
}
if (imWindowChanged) {
mWindowsChanged = true;
displayContent.setLayoutNeeded();
newFocus = mRoot.computeFocusedWindow();
}
if (DEBUG_FOCUS_LIGHT || localLOGV) Slog.v(TAG_WM, "Changing focus from " +
mCurrentFocus + " to " + newFocus + " Callers=" + Debug.getCallers(4));
final WindowState oldFocus = mCurrentFocus;
mCurrentFocus = newFocus;
mLosingFocus.remove(newFocus);
if (mCurrentFocus != null) {
mWinAddedSinceNullFocus.clear();
mWinRemovedSinceNullFocus.clear();
}
int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
if (imWindowChanged && oldFocus != mInputMethodWindow) {
// Focus of the input method window changed. Perform layout if needed.
if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
displayContent.performLayout(true /*initial*/, updateInputWindows);
focusChanged &= ~FINISH_LAYOUT_REDO_LAYOUT;
} else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
// Client will do the layout, but we need to assign layers
// for handleNewWindowLocked() below.
displayContent.assignWindowLayers(false /* setLayoutNeeded */);
}
}
if ((focusChanged & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
// The change in focus caused us to need to do a layout. Okay.
displayContent.setLayoutNeeded();
if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
displayContent.performLayout(true /*initial*/, updateInputWindows);
}
}
if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
// If we defer assigning layers, then the caller is responsible for
// doing this part.
mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
}
displayContent.adjustForImeIfNeeded();
// We may need to schedule some toast windows to be removed. The toasts for an app that
// does not have input focus are removed within a timeout to prevent apps to redress
// other apps' UI.
displayContent.scheduleToastWindowsTimeoutIfNeededLocked(oldFocus, newFocus);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return true;
}
return false;
}
示例-添加一个Dialog和添加一个PopupMenu的区别
添加一个Dialog
adb shell dumpsys window w
Window #5 Window{7425a59 u0 com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.ActivityA}:
mDisplayId=0 stackId=3 mSession=Session{f547a5 6170:u0a10159} mClient=android.os.BinderProxy@ae5fea0
mOwnerUid=10159 mShowToOwnerOnly=true package=com.test.weijuncheng.testactivity appop=NONE
mAttrs={(0,0)(wrapxwrap) gr=CENTER sim={adjust=pan forwardNavigation} blurRatio=1.0 blurMode=0 ty=APPLICATION fmt=TRANSLUCENT wanim=0x10302f9 surfaceInsets=Rect(88, 88 - 88, 88)
fl=DIM_BEHIND ALT_FOCUSABLE_IM SPLIT_TOUCH HARDWARE_ACCELERATED}
Requested w=1024 h=537 mLayoutSeq=101
mBaseLayer=21000 mSubLayer=0 mAnimLayer=0+=0 mLastLayer=0
mToken=AppWindowToken{171b00d token=Token{a530aa4 ActivityRecord{2836537 u0 com.test.weijuncheng.testactivity/.ActivityA t110}}}
mAppToken=AppWindowToken{171b00d token=Token{a530aa4 ActivityRecord{2836537 u0 com.test.weijuncheng.testactivity/.ActivityA t110}}}
isAnimatingWithSavedSurface()= mAppDied=false drawnStateEvaluated=true mightAffectAllDrawn=true
mViewVisibility=0x0 mHaveFrame=true mObscured=false
mSeq=0 mSystemUiVisibility=0x0
mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]
mFullConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
mLastReportedConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
mHasSurface=true isReadyForDisplay()=true mWindowRemovalAllowed=false
mFrame=[28,884][1052,1421] last=[28,884][1052,1421]
Frames: containing=[0,96][1080,2210] parent=[0,96][1080,2210]
display=[0,96][1080,2210] overscan=[0,96][1080,2210]
content=[28,884][1052,1421] visible=[28,884][1052,1421]
decor=[0,96][1080,2210]
outset=[0,0][0,0]
Cur insets: overscan=[0,0][0,0] content=[0,0][0,0] visible=[0,0][0,0] stable=[0,0][0,0] surface=[88,88][88,88] outsets=[0,0][0,0] cutout=DisplayCutout{insets=Rect(0, 0 - 0, 0) boundingRect=Rect(422, -884 - 602, -804)}
Lst insets: overscan=[0,0][0,0] content=[0,0][0,0] visible=[0,0][0,0] stable=[0,0][0,0] physical=[0,0][0,0] outset=[0,0][0,0] cutout=com.android.server.wm.utils.WmDisplayCutout@19b15ef2
WindowStateAnimator{673d0cb com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.ActivityA}:
mAnimationIsEntrance=true mSurface=Surface(name=com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.ActivityA)/@0x89dc61e
Surface: shown=true layer=0 alpha=1.0 rect=(0.0,0.0) 1200 x 713 transform=(1.0, 0.0, 1.0, 0.0)
mDrawState=HAS_DRAWN mLastHidden=false
mSystemDecorRect=[0,0][1024,537] mLastClipRect=[0,0][1200,713]
mHandleByGesture=false
isOnScreen=true
isVisible=true
Window #6 Window{13922b1 u0 com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.ActivityA}:
mDisplayId=0 stackId=3 mSession=Session{f547a5 6170:u0a10159} mClient=android.os.BinderProxy@ac3d158
mOwnerUid=10159 mShowToOwnerOnly=true package=com.test.weijuncheng.testactivity appop=NONE
mAttrs={(0,0)(fillxfill) sim={adjust=pan forwardNavigation} blurRatio=1.0 blurMode=0 ty=BASE_APPLICATION wanim=0x10302f8
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}
Requested w=1080 h=2340 mLayoutSeq=101
mBaseLayer=21000 mSubLayer=0 mAnimLayer=0+=0 mLastLayer=0
mToken=AppWindowToken{171b00d token=Token{a530aa4 ActivityRecord{2836537 u0 com.test.weijuncheng.testactivity/.ActivityA t110}}}
mAppToken=AppWindowToken{171b00d token=Token{a530aa4 ActivityRecord{2836537 u0 com.test.weijuncheng.testactivity/.ActivityA t110}}}
isAnimatingWithSavedSurface()= mAppDied=false drawnStateEvaluated=true mightAffectAllDrawn=true
mViewVisibility=0x0 mHaveFrame=true mObscured=false
mSeq=0 mSystemUiVisibility=0x0
mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]
mFullConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
mLastReportedConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
mHasSurface=true isReadyForDisplay()=true mWindowRemovalAllowed=false
mFrame=[0,0][1080,2340] last=[0,0][1080,2340]
Frames: containing=[0,0][1080,2340] parent=[0,0][1080,2340]
display=[0,0][1080,2340] overscan=[0,0][1080,2340]
content=[0,96][1080,2210] visible=[0,96][1080,2210]
decor=[0,0][1080,2340]
outset=[0,0][0,0]
Cur insets: overscan=[0,0][0,0] content=[0,96][0,130] visible=[0,96][0,130] stable=[0,96][0,130] surface=[0,0][0,0] outsets=[0,0][0,0] cutout=DisplayCutout{insets=Rect(0, 80 - 0, 0) boundingRect=Rect(450, 0 - 630, 80)}
Lst insets: overscan=[0,0][0,0] content=[0,96][0,130] visible=[0,96][0,130] stable=[0,96][0,130] physical=[0,0][0,0] outset=[0,0][0,0] cutout=com.android.server.wm.utils.WmDisplayCutout@216dfc9d
WindowStateAnimator{eff0a8 com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.ActivityA}:
mSurface=Surface(name=com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.ActivityA)/@0x3cbe396
Surface: shown=true layer=0 alpha=1.0 rect=(0.0,0.0) 1080 x 2340 transform=(1.0, 0.0, 1.0, 0.0)
mDrawState=HAS_DRAWN mLastHidden=false
mSystemDecorRect=[0,0][1080,2340] mLastClipRect=[0,0][1080,2340]
mHandleByGesture=false
isOnScreen=true
isVisible=true
Window #7 Window{9dfb88 u0 com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.MainActivity}:
mDisplayId=0 stackId=2 mSession=Session{f547a5 6170:u0a10159} mClient=android.os.BinderProxy@5f9bb2b
mOwnerUid=10159 mShowToOwnerOnly=true package=com.test.weijuncheng.testactivity appop=NONE
mAttrs={(0,0)(fillxfill) sim={adjust=pan forwardNavigation} blurRatio=1.0 blurMode=0 ty=BASE_APPLICATION wanim=0x10302f8
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}
Requested w=1080 h=2340 mLayoutSeq=68
mBaseLayer=21000 mSubLayer=0 mAnimLayer=0+=0 mLastLayer=0
mToken=AppWindowToken{79c7276 token=Token{5892111 ActivityRecord{354d38 u0 com.test.weijuncheng.testactivity/.MainActivity t109}}}
mAppToken=AppWindowToken{79c7276 token=Token{5892111 ActivityRecord{354d38 u0 com.test.weijuncheng.testactivity/.MainActivity t109}}}
isAnimatingWithSavedSurface()= mAppDied=false drawnStateEvaluated=true mightAffectAllDrawn=true
mViewVisibility=0x8 mHaveFrame=true mObscured=true
mSeq=0 mSystemUiVisibility=0x0
mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]
mFullConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
mLastReportedConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
mHasSurface=false isReadyForDisplay()=false mWindowRemovalAllowed=false
mFrame=[0,0][1080,2340] last=[0,0][1080,2340]
Frames: containing=[0,0][1080,2340] parent=[0,0][1080,2340]
display=[0,0][1080,2340] overscan=[0,0][1080,2340]
content=[0,96][1080,2210] visible=[0,96][1080,2210]
decor=[0,0][1080,2340]
outset=[0,0][0,0]
Cur insets: overscan=[0,0][0,0] content=[0,96][0,130] visible=[0,96][0,130] stable=[0,96][0,130] surface=[0,0][0,0] outsets=[0,0][0,0] cutout=DisplayCutout{insets=Rect(0, 80 - 0, 0) boundingRect=Rect(450, 0 - 630, 80)}
Lst insets: overscan=[0,0][0,0] content=[0,96][0,130] visible=[0,96][0,130] stable=[0,96][0,130] physical=[0,0][0,0] outset=[0,0][0,0] cutout=com.android.server.wm.utils.WmDisplayCutout@216dfc9d
WindowStateAnimator{b6cd7c1 com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.MainActivity}:
mDrawState=NO_SURFACE mLastHidden=true
mSystemDecorRect=[0,0][1080,2340] mLastClipRect=[0,0][1080,2340]
mHandleByGesture=false
isOnScreen=false
isVisible=false
注意Session,token,mAttrs.ty
Dialog也有自己对应的Window,DecorView,ViewRootImpl
Dialog#show
/**
* Start the dialog and display it on screen. The window is placed in the
* application layer and opaque. Note that you should not override this
* method to do initialization when the dialog is shown, instead implement
* that in {@link #onStart}.
*/
public void show() {
if (mShowing) {
if (mDecor != null) {
if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
}
mDecor.setVisibility(View.VISIBLE);
}
return;
}
mCanceled = false;
if (!mCreated) {
dispatchOnCreate(null);
} else {
// Fill the DecorView in on any configuration changes that
// may have occured while it was removed from the WindowManager.
final Configuration config = mContext.getResources().getConfiguration();
mWindow.getDecorView().dispatchConfigurationChanged(config);
}
onStart();
mDecor = mWindow.getDecorView();
if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
final ApplicationInfo info = mContext.getApplicationInfo();
mWindow.setDefaultIcon(info.icon);
mWindow.setDefaultLogo(info.logo);
mActionBar = new WindowDecorActionBar(this);
}
WindowManager.LayoutParams l = mWindow.getAttributes();
boolean restoreSoftInputMode = false;
if ((l.softInputMode
& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
l.softInputMode |=
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
restoreSoftInputMode = true;
}
mWindowManager.addView(mDecor, l); //添加Dialog对应window
if (restoreSoftInputMode) {
l.softInputMode &=
~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
}
mShowing = true;
sendShowMessage(); //使Dialog显示出来
}
popupMenu的添加
调用PopupWindow的showAsDropDow
PopupWindow#showAsDropDow
/**
* Displays the content view in a popup window anchored to the corner of
* another view. The window is positioned according to the specified
* gravity and offset by the specified x and y coordinates.
*
* If there is not enough room on screen to show the popup in its entirety,
* this method tries to find a parent scroll view to scroll. If no parent
* view can be scrolled, the specified vertical gravity will be ignored and
* the popup will anchor itself such that it is visible.
*
* If the view later scrolls to move anchor
to a different
* location, the popup will be moved correspondingly.
*
* @param anchor the view on which to pin the popup window
* @param xoff A horizontal offset from the anchor in pixels
* @param yoff A vertical offset from the anchor in pixels
* @param gravity Alignment of the popup relative to the anchor
*
* @see #dismiss()
*/
public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
if (isShowing() || !hasContentView()) {
return;
}
TransitionManager.endTransitions(mDecorView);
attachToAnchor(anchor, xoff, yoff, gravity);
mIsShowing = true;
mIsDropdown = true;
final WindowManager.LayoutParams p =
createPopupLayoutParams(anchor.getApplicationWindowToken());
preparePopup(p);
final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff,
p.width, p.height, gravity, mAllowScrollingAnchorParent);
updateAboveAnchor(aboveAnchor);
p.accessibilityIdOfAnchor = (anchor != null) ? anchor.getAccessibilityViewId() : -1;
invokePopup(p);
}
PopupWindow#invokePopup
/**
* Invoke the popup window by adding the content view to the window
* manager.
*
* The content view must be non-null when this method is invoked.
*
* @param p the layout parameters of the popup's content view
*/
private void invokePopup(WindowManager.LayoutParams p) {
if (mContext != null) {
p.packageName = mContext.getPackageName();
}
final PopupDecorView decorView = mDecorView;
decorView.setFitsSystemWindows(mLayoutInsetDecor);
setLayoutDirectionFromAnchor();
mWindowManager.addView(decorView, p); //WindowManagerImpl的addView,将decorView添加到window中
if (mEnterTransition != null) {
decorView.requestEnterTransition(mEnterTransition);
}
}
一个Window对应一个WindowManagerImpl
WindowManagerImpl#addView->WindowManagerGlobal#addView -> 其中设置panelParentView(为MainActivity对应的decorView),创建decorView对应的ViewRootImpl,添加mViews,mRoots,mParams->ViewRootImpl#setView->WindowManagerService#addWindow
addWindow子窗口查找相应父窗口
if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
parentWindow = windowForClientLocked(null, attrs.token, false); //得到的parentWindow为MainActivity对应的PhoneWindow
if (parentWindow == null) {
Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
&& parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
}
addWindow创建子窗口WindowState
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid,
session.mCanAddInternalSystemWindow);
根据(WindowToken)token和parentWindow等创建popupWindow对应的WindowState parentWindow用于计算mBaseLayer的值
WindowState构造函数中
if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
mIsChildWindow = true;
if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + parentWindow);
parentWindow.addChild(this, sWindowSubLayerComparator); //Activity父窗口addChild添加子窗口
mLayoutAttached = mAttrs.type !=
WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
mIsImWindow = parentWindow.mAttrs.type == TYPE_INPUT_METHOD
|| parentWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
mIsWallpaper = parentWindow.mAttrs.type == TYPE_WALLPAPER;
}
WindowContanier#addChild
此时this为Activity对应 WindowState
/**
* Adds the input window container has a child of this container in order based on the input
* comparator.
* @param child The window container to add as a child of this window container.
* @param comparator Comparator to use in determining the position the child should be added to.
* If null, the child will be added to the top.
*/
@CallSuper
protected void addChild(E child, Comparator 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); //对子窗口,在父窗口对应的WindowState中的mChildren中添加子窗口对应的WindowState
}
onChildAdded(child);
// Set the parent after we've actually added a child in case a subclass depends on this.
child.setParent(this);
}
WindowContainer#setParent
final protected void setParent(WindowContainer parent) {
mParent = parent; //设置popupWindow的 mParent属性
// Removing parent usually means that we've detached this entity to destroy it or to attach
// to another parent. In both cases we don't need to update the configuration now.
if (mParent != null) {
// Update full configuration of this container and all its children.
onConfigurationChanged(mParent.getConfiguration());
// Update merged override configuration of this container and all its children.
onMergedOverrideConfigurationChanged();
}
onParentSet();
}
调用到WindowToken中的addWindow
此时this为popupWindow对应 WindowState(对于PopupMenu,子窗口直接返回)
void addWindow(final WindowState win) {
if (DEBUG_FOCUS) Slog.d(TAG_WM,
"addWindow: win=" + win + " Callers=" + Debug.getCallers(5));
if (win.isChildWindow()) {
// Child windows are added to their parent windows.
return; //因为popupMenu是子窗口,直接return
}
if (!mChildren.contains(win)) {
if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
addChild(win, mWindowComparator);
mService.mWindowsChanged = true;
// TODO: Should we also be setting layout needed here and other places?
}
}
WindowState#onParentSet
@Override
void onParentSet() {
super.onParentSet();
setDrawnStateEvaluated(false /*evaluated*/);
getDisplayContent().reapplyMagnificationSpec();
}
WindowContainer#onParentSet
/**
* Callback that is triggered when @link WindowContainer#setParent(WindowContainer)} was called.
* Supposed to be overridden and contain actions that should be executed after parent was set.
*/
void onParentSet() {
if (mParent == null) {
return;
}
if (mSurfaceControl == null) {
// If we don't yet have a surface, but we now have a parent, we should
// build a surface.
mSurfaceControl = makeSurface().build();
getPendingTransaction().show(mSurfaceControl);
updateSurfacePosition();
} else {
// If we have a surface but a new parent, we just need to perform a reparent. Go through
// surface animator such that hierarchy is preserved when animating, i.e.
// mSurfaceControl stays attached to the leash and we just reparent the leash to the
// new parent.
reparentSurfaceControl(getPendingTransaction(), mParent.mSurfaceControl); //reparent Surface
}
// Either way we need to ask the parent to assign us a Z-order.
mParent.assignChildLayers(); //assign Z-order
scheduleAnimation();
}
WindowContainer#assignChildLayers
用于决定相关连的窗口间的z-order的
void assignChildLayers() {
assignChildLayers(getPendingTransaction());
scheduleAnimation();
}
void assignChildLayers(Transaction t) {
int layer = 0;
// We use two passes as a way to promote children which
// need Z-boosting to the end of the list.
for (int j = 0; j < mChildren.size(); ++j) {
final WindowContainer wc = mChildren.get(j);
wc.assignChildLayers(t);
if (!wc.needsZBoost()) {
wc.assignLayer(t, layer++);
}
}
for (int j = 0; j < mChildren.size(); ++j) {
final WindowContainer wc = mChildren.get(j);
if (wc.needsZBoost()) {
wc.assignLayer(t, layer++);
}
}
}
WindowState#assignChildLayers
// then we can drop all negative layering on the windowing side and simply inherit
// the default implementation here.
public void assignChildLayers(Transaction t) {
int layer = 1;
for (int i = 0; i < mChildren.size(); i++) {
final WindowState w = mChildren.get(i);
// APPLICATION_MEDIA_OVERLAY needs to go above APPLICATION_MEDIA
// while they both need to go below the main window. However the
// relative layering of multiple APPLICATION_MEDIA/OVERLAY has never
// been defined and so we can use static layers and leave it that way.
if (w.mAttrs.type == TYPE_APPLICATION_MEDIA) {
w.assignLayer(t, -2);
} else if (w.mAttrs.type == TYPE_APPLICATION_MEDIA_OVERLAY) {
w.assignLayer(t, -1);
} else {
w.assignLayer(t, layer);
}
w.assignChildLayers(t);
layer++;
}
}
WindowState#assignLayer
@Override
void assignLayer(Transaction t, int layer) {
// See comment in assignRelativeLayerForImeTargetChild
if (needsRelativeLayeringToIme()) {
getDisplayContent().assignRelativeLayerForImeTargetChild(t, this);
return;
}
super.assignLayer(t, layer);
}
WindowContainer#assignLayer
void assignLayer(Transaction t, int layer) {
final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
if (mSurfaceControl != null && changed) {
setLayer(t, layer);
mLastLayer = layer;
mLastRelativeToLayer = null;
}
}
SurfaceAnimator#setLayer
/**
* Sets the layer of the surface.
*
* When the layer of the surface needs to be adjusted, we need to set it on the leash if the
* surface is reparented to the leash. This method takes care of that.
*/
void setLayer(Transaction t, int layer) {
t.setLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), layer);
}
SurfaceControl#setLayer
public Transaction setLayer(SurfaceControl sc, int z) {
sc.checkNotReleased();
nativeSetLayer(mNativeObject, sc.mNativeObject, z);
return this;
}
SurfaceControl后续再看,但是应该是由layer的值来决定,本质上是由mChildren的顺序再决定,也就是addChild时的comparator来决定
对于子窗口,由mSubLayer决定
/**
* Compares two window sub-layers and returns -1 if the first is lesser than the second in terms
* of z-order and 1 otherwise.
*/
private static final Comparator sWindowSubLayerComparator =
new Comparator() {
@Override
public int compare(WindowState w1, WindowState w2) {
final int layer1 = w1.mSubLayer;
final int layer2 = w2.mSubLayer;
if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0 )) {
// We insert the child window into the list ordered by
// the sub-layer. For same sub-layers, the negative one
// should go below others; the positive one should go
// above others.
return -1;
}
return 1;
};
};
对于Dialog的情况(Dialog不是子窗口)
90 /**
91 * Compares two child window of this token and returns -1 if the first is lesser than the
92 * second in terms of z-order and 1 otherwise.
93 */
94 private final Comparator mWindowComparator =
95 (WindowState newWindow, WindowState existingWindow) -> {
96 final WindowToken token = WindowToken.this;
97 if (newWindow.mToken != token) {
98 throw new IllegalArgumentException("newWindow=" + newWindow
99 + " is not a child of token=" + token);
100 }
101
102 if (existingWindow.mToken != token) {
103 throw new IllegalArgumentException("existingWindow=" + existingWindow
104 + " is not a child of token=" + token);
105 }
106
107 return isFirstChildWindowGreaterThanSecond(newWindow, existingWindow) ? 1 : -1;
108 };
183 /**
184 * Returns true if the new window is considered greater than the existing window in terms of
185 * z-order.
186 */
187 protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
188 WindowState existingWindow) {
189 // New window is considered greater if it has a higher or equal base layer.
190 return newWindow.mBaseLayer >= existingWindow.mBaseLayer;
191 }
针对Dialog这种情况,其WindowState的mParent为AppWindowToken,和普通Activity一样
popupMenu属于子窗口
Window #5 Window{a45a614 u0 PopupWindow:6a36032}:
mDisplayId=0 stackId=1 mSession=Session{552cc8e 5068:u0a10160} mClient=android.os.BinderProxy@5da8867
mOwnerUid=10160 mShowToOwnerOnly=true package=com.test.weijuncheng.testactivity appop=NONE
mAttrs={(0,382)(539x396) gr=TOP START CENTER DISPLAY_CLIP_VERTICAL sim={state=unchanged adjust=resize} blurRatio=1.0 blurMode=0 ty=APPLICATION_SUB_PANEL fmt=TRANSLUCENT surfaceInsets=Rect(88, 88 - 88, 88) (manual)
fl=LAYOUT_NO_LIMITS ALT_FOCUSABLE_IM WATCH_OUTSIDE_TOUCH SPLIT_TOUCH HARDWARE_ACCELERATED FLAG_LAYOUT_ATTACHED_IN_DECOR
pfl=WILL_NOT_REPLACE_ON_RELAUNCH LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME}
Requested w=539 h=396 mLayoutSeq=290
mParentWindow=Window{a1d1045 u0 com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.MainActivity} mLayoutAttached=true
mBaseLayer=21000 mSubLayer=2 mAnimLayer=0+=0 mLastLayer=0
mToken=AppWindowToken{8275ffc token=Token{e38d8ef ActivityRecord{ebfa1ce u0 com.test.weijuncheng.testactivity/.MainActivity t38}}}
mAppToken=AppWindowToken{8275ffc token=Token{e38d8ef ActivityRecord{ebfa1ce u0 com.test.weijuncheng.testactivity/.MainActivity t38}}}
isAnimatingWithSavedSurface()= mAppDied=false drawnStateEvaluated=true mightAffectAllDrawn=true
mViewVisibility=0x0 mHaveFrame=true mObscured=false
mSeq=0 mSystemUiVisibility=0x0
mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]
mFullConfiguration={1.0 ?mcc?mnc [en_GB] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActiv
ityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
mLastReportedConfiguration={1.0 ?mcc?mnc [en_GB] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscree
n mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
mHasSurface=true isReadyForDisplay()=true mWindowRemovalAllowed=false
mFrame=[0,382][539,778] last=[0,382][539,778]
Frames: containing=[0,0][1080,2340] parent=[0,0][1080,2340]
display=[-10000,-10000][10000,10000] overscan=[-10000,-10000][10000,10000]
content=[0,382][539,778] visible=[0,382][539,778]
decor=[0,0][1080,2340]
outset=[0,0][0,0]
Cur insets: overscan=[0,0][0,0] content=[0,0][0,0] visible=[0,0][0,0] stable=[0,0][0,0] surface=[88,88][88,88] outsets=[0,0][0,0] cutout=DisplayCutout{insets=Rect(0, 0 - 0, 0) boundingRect=Rect(450, -382 - 630, -302)}
Lst insets: overscan=[0,0][0,0] content=[0,0][0,0] visible=[0,0][0,0] stable=[0,0][0,0] physical=[0,0][0,0] outset=[0,0][0,0] cutout=com.android.server.wm.utils.WmDisplayCutout@1a3bc8b1
WindowStateAnimator{c9986d4 PopupWindow:6a36032}:
mSurface=Surface(name=PopupWindow:6a36032)/@0x58cc9b9
Surface: shown=true layer=0 alpha=1.0 rect=(0.0,0.0) 715 x 572 transform=(1.0, 0.0, 1.0, 0.0)
mDrawState=HAS_DRAWN mLastHidden=false
mSystemDecorRect=[0,0][539,396] mLastClipRect=[0,0][715,572]
mHandleByGesture=false
isOnScreen=true
isVisible=true
Window #6 Window{a1d1045 u0 com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.MainActivity}:
mDisplayId=0 stackId=1 mSession=Session{552cc8e 5068:u0a10160} mClient=android.os.BinderProxy@fbb68bc
mOwnerUid=10160 mShowToOwnerOnly=true package=com.test.weijuncheng.testactivity appop=NONE
mAttrs={(0,0)(fillxfill) sim={adjust=pan forwardNavigation} blurRatio=1.0 blurMode=0 ty=BASE_APPLICATION wanim=0x10302f8
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}
Requested w=1080 h=2340 mLayoutSeq=290
mBaseLayer=21000 mSubLayer=0 mAnimLayer=0+=0 mLastLayer=0
mToken=AppWindowToken{8275ffc token=Token{e38d8ef ActivityRecord{ebfa1ce u0 com.test.weijuncheng.testactivity/.MainActivity t38}}}
mAppToken=AppWindowToken{8275ffc token=Token{e38d8ef ActivityRecord{ebfa1ce u0 com.test.weijuncheng.testactivity/.MainActivity t38}}}
isAnimatingWithSavedSurface()= mAppDied=false drawnStateEvaluated=true mightAffectAllDrawn=true
mViewVisibility=0x0 mHaveFrame=true mObscured=false
mSeq=0 mSystemUiVisibility=0x0
mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]
mFullConfiguration={1.0 ?mcc?mnc [en_GB] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
mLastReportedConfiguration={1.0 ?mcc?mnc [en_GB] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
mHasSurface=true isReadyForDisplay()=true mWindowRemovalAllowed=false
mFrame=[0,0][1080,2340] last=[0,0][1080,2340]
Frames: containing=[0,0][1080,2340] parent=[0,0][1080,2340]
display=[0,0][1080,2340] overscan=[0,0][1080,2340]
content=[0,96][1080,2210] visible=[0,96][1080,2210]
decor=[0,0][1080,2340]
outset=[0,0][0,0]
Cur insets: overscan=[0,0][0,0] content=[0,96][0,130] visible=[0,96][0,130] stable=[0,96][0,130] surface=[0,0][0,0] outsets=[0,0][0,0] cutout=DisplayCutout{insets=Rect(0, 80 - 0, 0) boundingRect=Rect(450, 0 - 630, 80)}
Lst insets: overscan=[0,0][0,0] content=[0,96][0,130] visible=[0,96][0,130] stable=[0,96][0,130] physical=[0,0][0,0] outset=[0,0][0,0] cutout=com.android.server.wm.utils.WmDisplayCutout@216dfc9d
WindowStateAnimator{ae602ee com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.MainActivity}:
mSurface=Surface(name=com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.MainActivity)/@0x6b307d
Surface: shown=true layer=0 alpha=1.0 rect=(0.0,0.0) 1080 x 2340 transform=(1.0, 0.0, 1.0, 0.0)
mDrawState=HAS_DRAWN mLastHidden=false
mSystemDecorRect=[0,0][1080,2340] mLastClipRect=[0,0][1080,2340]
mHandleByGesture=false
isOnScreen=true
isVisible=true
注意token,mSubLayer,mFrame=[0,382]539,778等属性
总结
那么目前看起来,AppWindowToken和WindowState 都可能有多个mChildren (list of WindowState)
AppWindowToken可能包含多个WindowState;每个WindowState也可能包含除自己以外的WindowState
第一种情况:
AppWindowToken可能包含多个WindowState
Activity页面起一个Dialog (AppWindowToken包含两个WindowState,分别代表Activity和Dialog的WindowState,其mChildren.size()==0)
第二种情况:
每个WindowState也可能包含除自己以外的WindowState
Activity中起一个PopupMenu(AppWindowToken的mChildren只包含一个WindowState(代表Activity),这个WindowState的mChildren.size()==1,其值为PopupWindow的WindowState)
总结
z-order看起来由mBaseLayer mSubLayer stack WindowList (mChildren)的顺序等共同决定的
ViewRootImpl是ViewRoot的实现类,ViewRoot不是view,而是整个ViewTree的管理者。
DecorView是整个ViewTree的根布局视图
Activity有个PhoneWinodw; 然后再Activity resume的过程中,通过addView将DecorView安装到PhoneWinodw的下,并创建对应的ViewRootImpl来管理;并在此过程中创建WMS端对应的WindowState