Android28源码
Dialog通过Activity拿到的WindowManagerImpl是带mParentWindow的,这个mParentWindow就是Activity的PhoneWindow,在addview()时会使用mParentWindow修改LayoutParams,设置token。
这个token是ActivityRecord.appToken
1 使用Activity当做Content弹Dialog时,Dialog构造方法中拿到的WindowManagerImpl对象是Activity中创建的,这个WindowManagerImpl对象的mParentWindow就是Activity的PhoneWindow。
2 在Dialog.show()时会用这个WindowManagerImpl对象addView(),会在WindowManagerGlobal.addview(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow)中使用parentWindow修正params(parentWindow.adjustLayoutParamsForSubWindow(wparams)),会把token给设置上。
Dialog的构造方法和show()方法:
Dialog.java
Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
......
// 调用Activity.getSystemService(Context.WINDOW_SERVICE)
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
final Window w = new PhoneWindow(mContext);
mWindow = w;
w.setCallback(this);
w.setOnWindowDismissedCallback(this);
w.setOnWindowSwipeDismissedCallback(() -> {
if (mCancelable) { cancel(); }
});
w.setWindowManager(mWindowManager, null, null);
......
}
public void show() {
.......
mWindowManager.addView(mDecor, l);
.......
}
Activity.getSystemService()和attach()
Activity.java
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback) {
......
// 设置PhoneWindow的WindowManager, 把Activity的token传给PhoneWindow
// 这个token是ActivityRecord.appToken
mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
// 保存带parentWindow的WindowManagerImpl对象
mWindowManager = mWindow.getWindowManager();
......
}
public Object getSystemService(@ServiceName @NonNull String name) {
if (getBaseContext() == null) {
throw new IllegalStateException( "System services not available to Activities before onCreate()");
}
if (WINDOW_SERVICE.equals(name)) {
// 返回的是带parentWindow的WindowManagerImpl对象
return mWindowManager;
} else if (SEARCH_SERVICE.equals(name)) {
ensureSearchManager(); return mSearchManager;
}
return super.getSystemService(name);
}
子窗口的token:使用的DecorView.getWindowToken(),使用的ViewRootImpl.mWindow.asBinder(),Window的跨进程标识
应用窗口的token:使用的ActivityRecord.appToken,Activity的跨进程标识
WMS怎么使用token的??
Window.setWindowManager():创建一个带mParentWindow的WindowManagerImpl实例
Window.java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
// 通过wm创建一个新的WindowManagerImpl,parentWindow是当前window
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW){
// 子窗口处理
if (wp.token == null) {
View decor = peekDecorView();
if (decor != null) {
// 使用DecorView的token
// 这里的token是ViewRootImpl.mWindow.asBinder() window的标示
wp.token = decor.getWindowToken();
}
}
......
} else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW && wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
// 系统窗口处理,不用设置token
.......
} else {
// 应用窗口处理
......
if (wp.token == null) {
// 这个token是ActivityRecord.appToken,activity的跨进程标识
wp.token = mContainer == null ? mAppToken : mContainer.mAppToken; // 设置token
}
......
}
}
WindowManagerImpl.java
private WindowManagerImpl(Context context, Window parentWindow) {
mContext = context;
mParentWindow = parentWindow;
}
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
.......
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
// 使用parentWindow修正wparams
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
......
}
......
}