记录一个WMS的问题,如何修改或者添加一个WMS的层级
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow,
PowerManagerWrapper powerManagerWrapper) {
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);
} 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;
}
可以看到这里有个baseLayer这个属性,了解WMS的应该知道WindowState是什么东西
这个mbaseLayer的值 最终会调用到 mPolicy.getWindowLayerLw
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:
return 4;
case TYPE_INPUT_CONSUMER:
return 5;
case TYPE_SYSTEM_DIALOGreturn 6;
case TYPE_TOAST:
// toasts and the plugged-in battery thing
return 7;
case TYPE_PRIORITY_PHONE:
// SIM errors and unlock. Not sure if this really should be in a high layer.
return 8;
case TYPE_SYSTEM_ALERT:
// like the ANR / app crashed dialogs
// Type is deprecated for non-system apps. For system apps, this type should be
// return canAddInternalSystemWindow ? 12 : 9;
case TYPE_APPLICATION_OVERLAY:
return 11;
case TYPE_INPUT_METHOD:
// on-screen keyboards and other such input method user interfaces go here.
return 13;
case TYPE_INPUT_METHOD_DIALOG:
// on-screen keyboards and other such input method user interfaces go here.
return 14;
case TYPE_STATUS_BAR:
return 15;
case TYPE_STATUS_BAR_ADDITIONAL:
return 16;
case TYPE_NOTIFICATION_SHADE:
return 17;
case TYPE_STATUS_BAR_SUB_PANEL:
return 18;
case TYPE_KEYGUARD_DIALOG:
return 19;
case TYPE_VOICE_INTERACTION_STARTING:
return 20;
case TYPE_VOICE_INTERACTION: // voice interaction layer should show above the lock screen.
return 21;
case TYPE_VOLUME_OVERLAY:
// the on-screen volume indicator and controller shown when the user
// changes the device volume
return 22;
。。。。省略
如果你需要新增一个层级很高的类型那么就新增一个新的参数即可新增一个新的层级
当然还需要跟APP对应起来
但是问题来了,WMS的baseLayer我去看了一下似乎没有直接跟SurfaceContorl关联起来,SurfaceContorl的setLayer没有直接set这个baseLayer
那么WMS的渲染层级到底怎么设置的??SurfaceContorl 跟这个baseLayer到底有什么关系?
其实这个baseLayer只是一个相对位置,并不是surfaceControl的真实位置,如果你dumpsurface
并不会dump到我们新增的window位置
WMS的排序是通过排序,而这个排序是当前这个window在集合里的位置
窗口次序的调整时机应该是有新窗口被添加或是旧的窗口被移除,不管是什么类型的窗口被添加到wms中都是走addWindow方法
final boolean suspended = mPmInternal.isPackageSuspended(win.getOwningPackage(),
UserHandle.getUserId(win.getOwningUid()));
win.setHiddenWhileSuspended(suspended);
final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty();
win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);
final AppWindowToken aToken = token.asAppWindowToken();
if (type == TYPE_APPLICATION_STARTING && aToken != null) {
aToken.startingWindow = win;
if (DEBUG_STARTING_WINDOW) Slog.v (TAG_WM, "addWindow: " + aToken
+ " startingWindow=" + win);
}
boolean imMayMove = true;
win.mToken.addWindow(win);
if (type == TYPE_INPUT_METHOD) {
win.mGivenInsetsPending = true;
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 ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
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;
}
}
这个地方有两个关键点
win.mToken.addWindow(win);添加到windowContainer中,此时会导致容器中的其他窗口位置会发生变化
WindowToken.java
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;
}
if (!mChildren.contains(win)) {//如果WindowContainer中没有添加过
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?
}
}
WindowContainer.java
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);
}
onChildAdded(child);
// Set the parent after we've actually added a child in case a subclass depends on this.
child.setParent(this);
}
//自定义的Comparator
private final Comparator mWindowComparator =
(WindowState newWindow, WindowState existingWindow) -> {
final WindowToken token = WindowToken.this;
if (newWindow.mToken != token) {//如果token不同,那么肯定不是一个容器
throw new IllegalArgumentException("newWindow=" + newWindow
+ " is not a child of token=" + token);
}
if (existingWindow.mToken != token) {//确保容器相同
throw new IllegalArgumentException("existingWindow=" + existingWindow
+ " is not a child of token=" + token);
}
return isFirstChildWindowGreaterThanSecond(newWindow, existingWindow) ? 1 : -1;
};
protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
WindowState existingWindow) {
// New window is considered greater if it has a higher or equal base layer.
return newWindow.mBaseLayer >= existingWindow.mBaseLayer;//比较baseLayer值
}
这里完成了在集合里的排序,可是跟surfaceControl怎么关联上的?
public void assignChildLayers(Transaction t) {
// The surface of the main window might be preserved. So the child window on top of the main
// window should be also on top of the preserved surface.
int layer = PRESERVED_SURFACE_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 belelow 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) {
if (mWinAnimator.hasSurface()) {
w.assignRelativeLayer(t, mWinAnimator.mSurfaceController.mSurfaceControl, -2);
} else {
w.assignLayer(t, -2);
}
} else if (w.mAttrs.type == TYPE_APPLICATION_MEDIA_OVERLAY) {
if (mWinAnimator.hasSurface()) {
w.assignRelativeLayer(t, mWinAnimator.mSurfaceController.mSurfaceControl, -1);
} else {
w.assignLayer(t, -1);
}
} else {
w.assignLayer(t, layer);
}
w.assignChildLayers(t);
layer++;
}
} 在这里进行layer++
最终会走到
WindowContainer::assignLayer
void assignLayer(Transaction t, int layer) {
// Don't assign layers while a transition animation is playing
// TODO(b/173528115): establish robust best-practices around z-order fighting.
if (!mTransitionController.canAssignLayers(this)) return;
final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
if (mSurfaceControl != null && changed) {
setLayer(t, layer);
mLastLayer = layer;
mLastRelativeToLayer = null;
}
}
这个 setLayer(t, layer);方法会最终setSurfaceControl的Layer层级
protected void setLayer(Transaction t, int layer) {
if (mSurfaceFreezer.hasLeash()) {
// When the freezer has created animation leash parent for the window, set the layer
// there instead.
mSurfaceFreezer.setLayer(t, layer);
} else {
// Route through surface animator to accommodate that our surface control might be
// attached to the leash, and leash is attached to parent container.
mSurfaceAnimator.setLayer(t, layer);
}
}
所以最终就会给到surfacecontrol
验证 在 getWindowLayerFromTypeLw新增36 mBaseLayer=361000 通过dump可以拿到
Window #2 Window{a06b8bf u0 com.example.myapplication}:
mDisplayId=0 rootTaskId=1 mSession=Session{5f8e963 10870:u0a10173} mClient=android.os.BinderProxy@9ff5e19
mOwnerUid=10173 showForAllUsers=true package=com.example.myapplication appop=NONE
mAttrs={(0,0)(2000000000x2000000000) gr=CENTER sim={adjust=pan} ty=TYPE_AUTO_CALL fmt=TRANSLUCENT
fl=NOT_FOCUSABLE HARDWARE_ACCELERATED
pfl=USE_BLAST INSET_PARENT_FRAME_BY_IME
bhv=DEFAULT
fitTypes=STATUS_BARS NAVIGATION_BARS CAPTION_BAR}
Requested w=3511296 h=3511296 mLayoutSeq=407
mBaseLayer=361000 mSubLayer=0 mToken=WindowToken{bcdede type=2101 android.os.BinderProxy@9ff5e19}
mViewVisibility=0x0 mHaveFrame=true mObscured=false
mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]
mFullConfiguration={1.0 ?mcc0mnc [zh_CN_#Hans] ldltr sw1440dp w2560dp h1154dp 160dpi xlrg long land car finger -keyb/v/h dpad/v winConfig={ mBounds=Rect(0, 0 - 2560, 1440) mAppBounds=Rect(0, 0 - 2560, 1296) mMaxBounds=Rect(0, 0 - 2560, 1440) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} s.1160 fontWeightAdjustment=0}
mLastReportedConfiguration={1.0 ?mcc0mnc [zh_CN_#Hans] ldltr sw1440dp w2560dp h1154dp 160dpi xlrg long land car finger -keyb/v/h dpad/v winConfig={ mBounds=Rect(0, 0 - 2560, 1440) mAppBounds=Rect(0, 0 - 2560, 1296) mMaxBounds=Rect(0, 0 - 2560, 1440) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} s.1160 fontWeightAdjustment=0}
mHasSurface=true isReadyForDisplay()=true mWindowRemovalAllowed=false
Frames: parent=[0,0][2560,1440] display=[0,0][2560,1440] frame=[0,0][2560,1440] last=[0,0][2560,1440] insetsChanged=false
surface=[0,0][0,0]
WindowStateAnimator{65e1e17 }:
mSurface=Surface(name=)/@0xd8137cb
Surface: shown=true layer=0 alpha=1.0 rect=(0.0,0.0) transform=(1.0, 0.0, 0.0, 1.0)
mDrawState=HAS_DRAWN mLastHidden=false
mEnterAnimationPending=false mSystemDecorRect=[0,0][0,0]
mForceSeamlesslyRotate=false seamlesslyRotate: pending=null isOnScreen=true
isVisible=true
keepClearAreas: restricted=[], unrestricted=[]
mPrepareSyncSeqId=0