win.hideLw(false);
} else {
win.showLw(false);
}
}
}
首先会判断当前WindowState是否能够被keyguard隐藏,这将直接影响到窗口的显示。如果能够被隐藏,则接下来会判断是否应该进行隐藏,如果需要进行隐藏,则调用WindowState#hideLw()进行隐藏,否则调用WindowState#showLw()进行显示。下面依次看下这个过程。
1.WindowState是否能够被keyguard隐藏
先来看如何确认WindowState是否能被Keyguard隐藏:
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
public boolean canBeHiddenByKeyguardLw(WindowState win) {
// 如果是Activity类型的WindowState,是否可见由ActivityRecord决定,不会被keyguard覆盖
if (win.getAppToken() != null) {
return false;
}
// 以下四个窗口类型,不会被Keyguard覆盖
switch (win.getAttrs().type) {
case TYPE_NOTIFICATION_SHADE:
case TYPE_STATUS_BAR:
case TYPE_NAVIGATION_BAR:
case TYPE_WALLPAPER:
return false;
default:
// 当前Win的layer是否小于
return getWindowLayerLw(win) < getWindowLayerFromTypeLw(TYPE_NOTIFICATION_SHADE);
}
}
以上流程说明,对于Activity窗口、四类系统窗口、以及窗口类型对应的Layer值大于TYPE_NOTIFICATION_SHADE类型窗口的Layer值的窗口,Keyguard是不会进行覆盖,除此之外的窗口,都会进行覆盖。
2.当前WindowState是否应该被覆盖
如果能够被覆盖,接下来会确认是否应该被覆盖:
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
private boolean shouldBeHiddenByKeyguard(WindowState win, WindowState imeTarget) {
final LayoutParams attrs = win.getAttrs();
…
// 如果当前窗口为IME窗口,且处于AOD状态,则对IME窗口进行隐藏
final boolean hideIme = win.isInputMethodWindow()
&& (mAodShowing || !mDefaultDisplayPolicy.isWindowManagerDrawComplete());
if (hideIme) {
return true;
}
//如果当前IME Target窗口存在且可见,且该IME Target能在锁屏上显示
final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleLw()
&& (imeTarget.canShowWhenLocked() || !canBeHiddenByKeyguardLw(imeTarget));
// 锁屏时显示IME窗口
boolean allowWhenLocked = win.isInputMethodWindow() && showImeOverKeyguard;
// 判断是否处于锁屏状态
final boolean isKeyguardShowing = mKeyguardDelegate.isShowing();
// 如果处于锁屏状态但锁屏被遮挡
if (isKeyguardShowing && isKeyguardOccluded()) {
allowWhenLocked |= win.canShowWhenLocked()
|| (attrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0;
}
// 返回"当前是否处于锁屏状态且不允许在锁屏上显示"
return isKeyguardShowing && !allowWhenLocked && win.getDisplayId() == DEFAULT_DISPLAY;
}
这个方法中,如果确定当前系统处于锁屏状态,且当前WindowState不允许在锁屏上显示,那么就说明需要被隐藏。
3.WindowState的隐藏和显示
如果满足条件,则通过hideLw()和showLw()方法,对WindowState进行隐藏操作,这里直接通过对WindowState#mPolicyVisibility
属性设置标记来实现:
// frameworks/base/services/core/java/com/android/server/wm/WindowState.java
boolean hideLw(boolean doAnimation, boolean requestAnim) {
…
if (!doAnimation) {
// 清除LEGACY_POLICY_VISIBILITY标记
clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
}
return true;
}
boolean showLw(boolean doAnimation, boolean requestAnim) {
// 添加LEGACY_POLICY_VISIBILITY标记
setPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
return true;
}
WindowState最终的显示与否,取决于许多影响其可见的变量。这里通过policy的方式,无论客户端和WMS状态是否让其显示,都会对窗口进行隐藏。
3.3.mApplySurfaceChangesTransaction
mApplyPostLayoutPolicy接口执行完毕后,接下来执行mApplySurfaceChangesTransaction
函数接口,在该接口中,会遍历各个WindowState,根据携带参数确定是否修改逻辑屏显示参数,并且对WindowState状态进行由COMMIT_DRAW_PENDING
到READY_TO_SHOW
的转变:
// frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
private final Consumer mApplySurfaceChangesTransaction = w -> {
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
// 确定当前WindowState是否被上面的WindowState遮挡
w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured;
// 当前没有遮挡其他窗口的WindowState,会获取win中设置的逻辑屏显示相关属性
if (!mTmpApplySurfaceChangesTransactionState.obscured) {
final boolean isDisplayed = w.isDisplayedLw