前面说到,应用程序添加窗口时,会在本地创建一个ViewRoot,然后通过IPC(进程间通信)调用WmS的Session的addWindow请求WmS创建窗口,下面来看看addWindow方法。

        addWindow方法定义在frameworks/base/services/java/com.android.server.WindowManagerService.java中,其代码如下所示:

public int addWindow(Session session, IWindow client,WindowManager.LayoutParams attrs, int viewVisibility,Rect outContentInsets, InputChannel outInputChannel) {// 是否有添加权限int res = mPolicy.checkAddPermission(attrs);if (res != WindowManagerImpl.ADD_OKAY) {return res;}boolean reportNewConfig = false;WindowState attachedWindow = null;WindowState win = null;synchronized(mWindowMap) {// Instantiating a Display requires talking with the simulator,// so don't do it until we know the system is mostly up and// running.// 是否存在显示设置if (mDisplay == null) {// 若不存在,则获取系统设置WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);mDisplay = wm.getDefaultDisplay();mInitialDisplayWidth = mDisplay.getWidth();mInitialDisplayHeight = mDisplay.getHeight();// 将Display存放到InputManager中mInputManager.setDisplaySize(0, mInitialDisplayWidth, mInitialDisplayHeight);reportNewConfig = true;}// 是否重复添加if (mWindowMap.containsKey(client.asBinder())) {Slog.w(TAG, "Window " + client + " is already added");return WindowManagerImpl.ADD_DUPLICATE_ADD;}// 是否子窗口if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {// 若为子窗口// 返回WmS中存在的对应父窗口,若不存在则返回nullattachedWindow = windowForClientLocked(null, attrs.token, false);// 若父窗口不存在,则表示添加了错误的子窗口if (attachedWindow == null) {Slog.w(TAG, "Attempted to add window with token that is not a window: "  + attrs.token + ".  Aborting.");return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;}// 若取得的父窗口也是子窗口,则表示添加了错误的子窗口,从这里来看,貌似窗口只有两层??if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW&& attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {Slog.w(TAG, "Attempted to add window with token that is a sub-window: "+ attrs.token + ".  Aborting.");return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;}}boolean addToken = false;// 在WmS中寻找对应的WindowTokenWindowToken token = mTokenMap.get(attrs.token);if (token == null) {if (attrs.type >= FIRST_APPLICATION_WINDOW&& attrs.type <= LAST_APPLICATION_WINDOW) {// 对于子窗口来说,WmS中必须有对应的Token才能添加Slog.w(TAG, "Attempted to add application window with unknown token "  + attrs.token + ".  Aborting.");return WindowManagerImpl.ADD_BAD_APP_TOKEN;}if (attrs.type == TYPE_INPUT_METHOD) {// 如果是内置的输入方法窗口,WmS中必须有对应的Token才能添加Slog.w(TAG, "Attempted to add input method window with unknown token "  + attrs.token + ".  Aborting.");return WindowManagerImpl.ADD_BAD_APP_TOKEN;}if (attrs.type == TYPE_WALLPAPER) {// 墙纸窗口,WmS中必须有对应的Token才能添加Slog.w(TAG, "Attempted to add wallpaper window with unknown token "  + attrs.token + ".  Aborting.");return WindowManagerImpl.ADD_BAD_APP_TOKEN;}// 创建窗口token = new WindowToken(attrs.token, -1, false);addToken = true;} else if (attrs.type >= FIRST_APPLICATION_WINDOW&& attrs.type <= LAST_APPLICATION_WINDOW) {// token不为null且是应用窗口AppWindowToken atoken = token.appWindowToken;if (atoken == null) {// appWindowToken值不能为空Slog.w(TAG, "Attempted to add window with non-application token "  + token + ".  Aborting.");return WindowManagerImpl.ADD_NOT_APP_TOKEN;} else if (atoken.removed) {// 试图使用存在的应用token添加窗口Slog.w(TAG, "Attempted to add window with exiting application token "  + token + ".  Aborting.");return WindowManagerImpl.ADD_APP_EXITING;}if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {// No need for this guy!// 窗口类型不能是应用启动时显示的窗口if (localLOGV) Slog.v(TAG, "**** NO NEED TO START: " + attrs.getTitle());return WindowManagerImpl.ADD_STARTING_NOT_NEEDED;}} else if (attrs.type == TYPE_INPUT_METHOD) {// 对于内置的输入方法窗口,token的windowType值要等于TYPE_INPUT_METHODif (token.windowType != TYPE_INPUT_METHOD) {Slog.w(TAG, "Attempted to add input method window with bad token "+ attrs.token + ".  Aborting.");  return WindowManagerImpl.ADD_BAD_APP_TOKEN;}} else if (attrs.type == TYPE_WALLPAPER) {// 对于墙纸窗口,token的windowType值要等于TYPE_WALLPAPERif (token.windowType != TYPE_WALLPAPER) {Slog.w(TAG, "Attempted to add wallpaper window with bad token "+ attrs.token + ".  Aborting.");  return WindowManagerImpl.ADD_BAD_APP_TOKEN;}}// 创建窗口win = new WindowState(session, client, token,attachedWindow, attrs, viewVisibility);if (win.mDeathRecipient == null) {// Client has apparently died, so there is no reason to// continue.// 客户端已被销毁,所以没必要继续Slog.w(TAG, "Adding window client " + client.asBinder()+ " that is dead, aborting.");return WindowManagerImpl.ADD_APP_EXITING;}// 如果是Toast,则此窗口不能够接收input事件mPolicy.adjustWindowParamsLw(win.mAttrs);// 判断添加的窗口是单例还是多例res = mPolicy.prepareAddWindowLw(win, attrs);if (res != WindowManagerImpl.ADD_OKAY) {// 是多例则直接返回return res;}// 如果输出的Channel,也即Pipe中的读通道为空if (outInputChannel != null) {// 创建通道String name = win.makeInputChannelName();InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);win.mInputChannel = inputChannels[0];inputChannels[1].transferToBinderOutParameter(outInputChannel);// 在InputManager中注册通道mInputManager.registerInputChannel(win.mInputChannel);}// From now on, no exceptions or errors allowed!res = WindowManagerImpl.ADD_OKAY;// 重置当前线程的IPC的IDfinal long origId = Binder.clearCallingIdentity();// 从上述代码中得出是否要添加Token,若是则添加Token添加到WmS中if (addToken) {mTokenMap.put(attrs.token, token);mTokenList.add(token);}// 将窗口添加到Session中win.attach();// 窗口信息添加到WmS中mWindowMap.put(client.asBinder(), win);if (attrs.type == TYPE_APPLICATION_STARTING &&token.appWindowToken != null) {// 对于应用启动时显示的窗口,设置tokentoken.appWindowToken.startingWindow = win;}boolean imMayMove = true;if (attrs.type == TYPE_INPUT_METHOD) {// 内置的输入方法窗口mInputMethodWindow = win;addInputMethodWindowToListLocked(win);imMayMove = false;} else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) {// 内置的输入方法对话框窗口mInputMethodDialogs.add(win);addWindowToListInOrderLocked(win, true);adjustInputMethodDialogsLocked();imMayMove = false;} else {// 其他窗口addWindowToListInOrderLocked(win, true);if (attrs.type == TYPE_WALLPAPER) {mLastWallpaperTimeoutTime = 0;adjustWallpaperWindowsLocked();} else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {adjustWallpaperWindowsLocked();}}win.mEnterAnimationPending = true;// 获取系统窗口区域的insetsmPolicy.getContentInsetHintLw(attrs, outContentInsets);if (mInTouchMode) {// 用户直接触摸的窗口res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE;}if (win == null || win.mAppToken == null || !win.mAppToken.clientHidden) {// 应用窗口res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE;}boolean focusChanged = false;if (win.canReceiveKeys()) {// 窗口需要按键事件// 更新焦点,将窗口信息写入了InputDispatcherfocusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS);if (focusChanged) {imMayMove = false;}}if (imMayMove) {// 若需要锁定的话,移动输入方法窗口moveInputMethodWindowsIfNeededLocked(false);}assignLayersLocked();// Don't do layout here, the window must call// relayout to be displayed, so we'll do it there.//dump();if (focusChanged) {finishUpdateFocusedWindowAfterAssignLayersLocked();}if (localLOGV) Slog.v(TAG, "New client " + client.asBinder()+ ": window=" + win);if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked()) {reportNewConfig = true;}}// sendNewConfiguration() checks caller permissions so we must call it with// privilege.  updateOrientationFromAppTokens() clears and resets the caller// identity anyway, so it's safe to just clear & restore around this whole// block.final long origId = Binder.clearCallingIdentity();if (reportNewConfig) {sendNewConfiguration();}Binder.restoreCallingIdentity(origId);return res;}

        有些东西还没摸明白,后面深入学习后再补一下。

        上文还说到,addWindow会将窗口信息写入InputDispatcher,其实在addWindow代码中有体现:

if (win.canReceiveKeys()) {// 窗口需要按键事件// 更新焦点,在这里,将窗口信息写入了InputDispatcherfocusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS);if (focusChanged) {imMayMove = false;}}

        至于如何写入InputDispatcher,下文分析。


更多相关文章

  1. Android(安卓)WebView属性及用法
  2. 关于android全屏截图,无需root,无状态栏,2个方法
  3. 通过EventBus更换android app主题
  4. Android(安卓)闹钟 开发过程记录(二)
  5. 编译源码生成的SDK,创建android project 没有proguard.cfg问题
  6. 导入android源码有错,R.java文件不能自动生成解决方法[转]
  7. android镜像制作方法
  8. 在Android(安卓)Studio上使用lambda
  9. Android设置launchMode为singleTask的Activity怎么刷新页面内容

随机推荐

  1. Android中一些错误
  2. android wifi 设置 控制开关
  3. 记录代码合并时产生的bug
  4. [置顶] Android Studio 配置
  5. Android(安卓)拍照强制横屏解决...
  6. Android linux adc驱动(s5pv210)
  7. android webview在弹出软键盘时,布局没有
  8. [置顶] Android基于XMPP Smack Openfire
  9. android之ListView与Adapter(结合JavaBea
  10. Android五大布局详解——LinearLayout(线