windowManager参数学习
ViewManager这个接口,只有三个方法,添加view,updateView布局,删除View
public interface ViewManager {
void addView(View var1, LayoutParams var2);
void updateViewLayout(View var1, LayoutParams var2);
void removeView(View var1);
}
The interface that apps use to talk to the window manager
一个WindowManager实例对应一个Display,获取WindowManager需要Context上下文(Context.getSystemService(Context.WINDOW_SERVICE))
对应其注释
@SystemService(Context.WINDOW_SERVICE)
public interface WindowManager extends ViewManager {
窗口的布局参数,这个是很重要的
public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
@WindowType
public int type;
//分为三种,APPLICATION,FIRST_SUB_WINDOW,SYSTEM,在WMS的方法addWindow时,根据其窗口类型的不同,其窗口得到不同WindoToken
这里,简单介绍一下处理的一个故障,与flsgs相关:
/** Window flag: as long as this window is visible to the user, keep
* the device's screen turned on and bright. */
public static final int FLAG_KEEP_SCREEN_ON = 0x00000080;
值得注意的是,只要Activity对应的WindowState带有这个标志位,即使Activity没有带点亮屏幕的标志位,屏幕也会被对应的WindowState点亮,这是R上新增的亮屏逻辑(PowerManagerservice的wakeUpNoUpdateLocked方法有点亮屏幕的原因)
有一些业务场景需要注意这个:如近感灭屏,第三方通话,Q上不会亮屏,R上会亮屏。Google dialer 52如前所述,最新的dialer已修改这个bug,需要应用做亮屏适配
Activity方面,主要是R上新增的接口containsTurnScreenOnWindow
boolean getTurnScreenOnFlag() {
return mTurnScreenOn || containsTurnScreenOnWindow();
}
private boolean containsTurnScreenOnWindow() {
// When we are relaunching, it is possible for us to be unfrozen before our previous
// windows have been added back. Using the cached value ensures that our previous
// showWhenLocked preference is honored until relaunching is complete.
if (isRelaunching()) {
return mLastContainsTurnScreenOnWindow;
}
//可以在这里添加打印log,便比较清楚了
for (int i = mChildren.size() - 1; i >= 0; i--) {
if ((mChildren.get(i).mAttrs.flags & LayoutParams.FLAG_TURN_SCREEN_ON) != 0) {
return true;
}
}
return false;
}
WindowState方面,主要新增的亮屏判断hasTurnScreenOnFlag
void prepareWindowToDisplayDuringRelayout(boolean wasVisible) {
// We need to turn on screen regardless of visibility.
final boolean hasTurnScreenOnFlag = (mAttrs.flags & FLAG_TURN_SCREEN_ON) != 0
|| (mActivityRecord != null && mActivityRecord.canTurnScreenOn());
这里再介绍一个处理的故障,与窗口令牌有关,主要是子窗口的可见性问题。
IBinder,这个是窗口令牌。但system窗口的这个属性没有,即mAttrs.token = null。所以在系统窗口上,添加popupWindow,会导致子窗口没有令牌,从而子窗口显示不出来
/**
* Identifier for this window. This will usually be filled in for
* you.
*/
public IBinder token = null;
在WMS#addWindow中
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);
需要做一定的修改:
IBinder parentWindow_Token = new IBinder();
if (hasParent){
parentWindow_Token = parentWindow.mAttrs.token != null ? parentWindow.mAttrs.token : parentWindow.mToken.token;
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow_Token : attrs.token);
}
packageName这个参数不为null,如果为null,会在ViewRootImpl的setView为其赋值的。
/**
* Name of the package owning this window.
*/
public String packageName = null;
if (mWindowAttributes.packageName == null) {
mWindowAttributes.packageName = mBasePackageName;
}
layoutInDisplayCutoutMode 刘海屏控制flag,应用布局,是否占用Notch区域。真正的全面屏,是没有Notch,市面的全面屏,都是根据这个flag,拉伸应用布局,使其占用Notch区域
参考资料:https://blog.csdn.net/yi_master/article/details/80309757
/**
* Controls how the window is laid out if there is a {@link DisplayCutout}.
*
* <p>
* Defaults to {@link #LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT}.
*
* @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
* @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
* @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
* @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
* @see DisplayCutout
* @see android.R.attr#windowLayoutInDisplayCutoutMode
* android:windowLayoutInDisplayCutoutMode
*/
@LayoutInDisplayCutoutMode
public int layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;