Android 9.0系统源码_窗口管理(三)WindowManagerService对窗口的管理过程

news/2025/1/17 14:36:05/

前言

上一篇我们具体分析了WindowManager的addView方法添加窗口的过程,我们知道WindowManager最终会调用到WindowManagerService的addWindow方法。本篇文章我们将在此基础上,具体来分析WindowManagerService的addWindow方法添加窗口的过程。这个方法的代码逻辑非常长,提前做好心理准备。

1、WindowManagerService的addWindow方法如下所示。

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public class WindowManagerService extends IWindowManager.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {//窗口管理策略的接口类,用来定义一个窗口策略所要遵循的通用规范,具体实现类为PhoneWindowManager。final WindowManagerPolicy mPolicy;public int addWindow(Session session, IWindow client, int seq,LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,Rect outContentInsets, Rect outStableInsets, Rect outOutsets,DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {int[] appOp = new int[1];int res = mPolicy.checkAddPermission(attrs, appOp);if (res != WindowManagerGlobal.ADD_OKAY) {return res;}...代码省略...}
}

addWindow方法首先会调用WindowManagerPolicy的checkAddPermission方法进行权限判断,WindowManagerPolicy是一个接口,具体实现者为PhoneWindowManager。

2、PhoneWindowManager的checkAddPermission方法如下所示。

frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

public class PhoneWindowManager implements WindowManagerPolicy {public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp) {final int type = attrs.type;final boolean isRoundedCornerOverlay =(attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;if (isRoundedCornerOverlay && mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW)!= PERMISSION_GRANTED) {return ADD_PERMISSION_DENIED;}outAppOp[0] = AppOpsManager.OP_NONE;//判断是不是一个合法的窗口类型,必须是应用窗口、子窗口、系统窗口三种类型中的一种。if (!((type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW)|| (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW)|| (type >= FIRST_SYSTEM_WINDOW && type <= LAST_SYSTEM_WINDOW))) {return WindowManagerGlobal.ADD_INVALID_TYPE;}if (type < FIRST_SYSTEM_WINDOW || type > LAST_SYSTEM_WINDOW) {// Window manager will make sure these are okay.return ADD_OKAY;}//如果不是系统弹窗if (!isSystemAlertWindowType(type)) {switch (type) {case TYPE_TOAST:// Only apps that target older than O SDK can add window without a token, after// that we require a token so apps cannot add toasts directly as the token is// added by the notification system.// Window manager does the checking for this.outAppOp[0] = OP_TOAST_WINDOW;return ADD_OKAY;case TYPE_DREAM:case TYPE_INPUT_METHOD:case TYPE_WALLPAPER:case TYPE_PRESENTATION:case TYPE_PRIVATE_PRESENTATION:case TYPE_VOICE_INTERACTION:case TYPE_ACCESSIBILITY_OVERLAY:case TYPE_QS_DIALOG:// The window manager will check these.return ADD_OKAY;}return mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW)== PERMISSION_GRANTED ? ADD_OKAY : ADD_PERMISSION_DENIED;}// Things get a little more interesting for alert windows...outAppOp[0] = OP_SYSTEM_ALERT_WINDOW;final int callingUid = Binder.getCallingUid();// system processes will be automatically granted privilege to drawif (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {return ADD_OKAY;}//获取弹窗对应的应用信息ApplicationInfo appInfo;try {appInfo = mContext.getPackageManager().getApplicationInfoAsUser(attrs.packageName,0 /* flags */,UserHandle.getUserId(callingUid));} catch (PackageManager.NameNotFoundException e) {appInfo = null;}if (appInfo == null || (type != TYPE_APPLICATION_OVERLAY && appInfo.targetSdkVersion >= O)) {/*** Apps targeting >= {@link Build.VERSION_CODES#O} are required to hold* {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW} (system signature apps)* permission to add alert windows that aren't* {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY}.*/return (mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW)== PERMISSION_GRANTED) ? ADD_OKAY : ADD_PERMISSION_DENIED;}// check if user has enabled this operation. SecurityException will be thrown if this app// has not been allowed by the userfinal int mode = mAppOpsManager.noteOpNoThrow(outAppOp[0], callingUid, attrs.packageName);switch (mode) {case AppOpsManager.MODE_ALLOWED:case AppOpsManager.MODE_IGNORED:// although we return ADD_OKAY for MODE_IGNORED, the added window will// actually be hidden in WindowManagerServicereturn ADD_OKAY;case AppOpsManager.MODE_ERRORED:// Don't crash legacy appsif (appInfo.targetSdkVersion < M) {return ADD_OKAY;}return ADD_PERMISSION_DENIED;default:// in the default mode, we will make a decision here based on// checkCallingPermission()return (mContext.checkCallingOrSelfPermission(SYSTEM_ALERT_WINDOW)== PERMISSION_GRANTED) ? ADD_OKAY : ADD_PERMISSION_DENIED;}}//是不是系统弹窗public static boolean isSystemAlertWindowType(int type) {switch (type) {case TYPE_PHONE:case TYPE_PRIORITY_PHONE:case TYPE_SYSTEM_ALERT:case TYPE_SYSTEM_ERROR:case TYPE_SYSTEM_OVERLAY:case TYPE_APPLICATION_OVERLAY:return true;}return false;}
}

checkAddPermission会做一些窗口类型以及安全相关的权限判断,并将结果返回赋值给res。如果res不等于WindowManagerGlobal.ADD_OKAY的话WindowManagerService的addWindow就会直接返回,而结合上一篇文章我们知道,该返回结果会被ViewRootImpl收到。

3、ViewRootImpl的setView方法收到返回值后的相关操作如下所示。

public final class ViewRootImpl implements ViewParent,View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {synchronized (this) {...代码省略...res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(),mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,mAttachInfo.mOutsets, mInputChannel);...代码省略...//会根据WindowManagerService返回的判断窗口是否添加成功,以便抛出各种异常if (res < WindowManagerGlobal.ADD_OKAY) {mAttachInfo.mRootView = null;mAdded = false;mFallbackEventHandler.setView(null);unscheduleTraversals();setAccessibilityFocus(null, null);switch (res) {case WindowManagerGlobal.ADD_BAD_APP_TOKEN:case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:throw new WindowManager.BadTokenException("Unable to add window -- token " + attrs.token+ " is not valid; is your activity running?");case WindowManagerGlobal.ADD_NOT_APP_TOKEN:throw new WindowManager.BadTokenException("Unable to add window -- token " + attrs.token+ " is not for an application");case WindowManagerGlobal.ADD_APP_EXITING:throw new WindowManager.BadTokenException("Unable to add window -- app for token " + attrs.token+ " is exiting");case WindowManagerGlobal.ADD_DUPLICATE_ADD:throw new WindowManager.BadTokenException("Unable to add window -- window " + mWindow+ " has already been added");case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:// Silently ignore -- we would have just removed it// right away, anyway.return;case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:throw new WindowManager.BadTokenException("Unable to add window "+ mWindow + " -- another window of type "+ mWindowAttributes.type + " already exists");case WindowManagerGlobal.ADD_PERMISSION_DENIED:throw new WindowManager.BadTokenException("Unable to add window "+ mWindow + " -- permission denied for window type "+ mWindowAttributes.type);case WindowManagerGlobal.ADD_INVALID_DISPLAY:throw new WindowManager.InvalidDisplayException("Unable to add window "+ mWindow + " -- the specified display can not be found");case WindowManagerGlobal.ADD_INVALID_TYPE:throw new WindowManager.InvalidDisplayException("Unable to add window "+ mWindow + " -- the specified window type "+ mWindowAttributes.type + " is not valid");}throw new RuntimeException("Unable to add window -- unknown error code " + res);}}
}

ViewRootImpl会根据WindowManagerService的返回值来判断窗口是否添加成功,以便决定是否抛出各种异常信息。

4、继续往下看WindowManagerService的addWindow方法。

public class WindowManagerService extends IWindowManager.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {public int addWindow(Session session, IWindow client, int seq,LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,Rect outContentInsets, Rect outStableInsets, Rect outOutsets,DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {...代码省略...boolean reportNewConfig = false;WindowState parentWindow = null;//父窗口long origId;final int callingUid = Binder.getCallingUid();//调用者idfinal int type = attrs.type;//窗口类型synchronized(mWindowMap) {if (!mDisplayReady) {throw new IllegalStateException("Display has not been initialialized");}//获取窗口需要添加的屏幕设备是否为空final DisplayContent displayContent = getDisplayContentOrCreate(displayId);if (displayContent == null) {Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "+ displayId + ".  Aborting.");return WindowManagerGlobal.ADD_INVALID_DISPLAY;}if (!displayContent.hasAccess(session.mUid)&& !mDisplayManagerInternal.isUidPresentOnDisplay(session.mUid, displayId)) {Slog.w(TAG_WM, "Attempted to add window to a display for which the application "+ "does not have access: " + displayId + ".  Aborting.");return WindowManagerGlobal.ADD_INVALID_DISPLAY;}if (mWindowMap.containsKey(client.asBinder())) {Slog.w(TAG_WM, "Window " + client + " is already added");return WindowManagerGlobal.ADD_DUPLICATE_ADD;}//判断窗口是否是子窗口类型if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {parentWindow = windowForClientLocked(null, attrs.token, false);//判断父类窗口是否为空if (parentWindow == null) {Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;}//判断父类窗口是否为子窗口类型if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW&& parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;}}...代码省略...}
}

上面代码主要做了两个关键判断。
1)通过窗口获取需要添加的具体屏幕设备是否为空,来决定是否需要返回异常。
2)如果窗口类型为子窗口,判断子窗口的父窗口是否为空以及父窗口的类型是否为子窗口来决定是否返回异常。

5、继续往下看WindowManagerService的addWindow方法。

public class WindowManagerService extends IWindowManager.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {public int addWindow(Session session, IWindow client, int seq,LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,Rect outContentInsets, Rect outStableInsets, Rect outOutsets,DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) { ...代码省略...AppWindowToken atoken = null;//是否有父窗口final boolean hasParent = parentWindow != null;// 获取当前Window的令牌WindowToken token = displayContent.getWindowToken(hasParent ? parentWindow.mAttrs.token : attrs.token);// 获取当前Window的跟类型final int rootType = hasParent ? parentWindow.mAttrs.type : type;boolean addToastWindowRequiresToken = false;if (token == null) {//如果Window的令牌为空if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {//应用程序窗口Slog.w(TAG_WM, "Attempted to add application window with unknown token "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}if (rootType == TYPE_INPUT_METHOD) {//输入法Slog.w(TAG_WM, "Attempted to add input method window with unknown token "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}if (rootType == TYPE_VOICE_INTERACTION) {Slog.w(TAG_WM, "Attempted to add voice interaction window with unknown token "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}if (rootType == TYPE_WALLPAPER) {//壁纸Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}if (rootType == TYPE_DREAM) {Slog.w(TAG_WM, "Attempted to add Dream window with unknown token "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}if (rootType == TYPE_QS_DIALOG) {Slog.w(TAG_WM, "Attempted to add QS dialog window with unknown token "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with unknown token "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}if (type == TYPE_TOAST) {// Apps targeting SDK above N MR1 cannot arbitrary add toast windows.if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,parentWindow)) {Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}}final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();final boolean isRoundedCornerOverlay =(attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;//为窗口创建隐式令牌token = new WindowToken(this, binder, type, false, displayContent,session.mCanAddInternalSystemWindow, isRoundedCornerOverlay);} else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {//令牌不为空,且属于应用程序窗口atoken = token.asAppWindowToken();if (atoken == null) {Slog.w(TAG_WM, "Attempted to add window with non-application token "+ token + ".  Aborting.");return WindowManagerGlobal.ADD_NOT_APP_TOKEN;} else if (atoken.removed) {Slog.w(TAG_WM, "Attempted to add window with exiting application token "+ token + ".  Aborting.");return WindowManagerGlobal.ADD_APP_EXITING;} else if (type == TYPE_APPLICATION_STARTING && atoken.startingWindow != null) {Slog.w(TAG_WM, "Attempted to add starting window to token with already existing"+ " starting window");return WindowManagerGlobal.ADD_DUPLICATE_ADD;}} else if (rootType == TYPE_INPUT_METHOD) {//令牌不为空,且属于输入法窗口if (token.windowType != TYPE_INPUT_METHOD) {//判断令牌类型是否为输入法Slog.w(TAG_WM, "Attempted to add input method window with bad token "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}} else if (rootType == TYPE_VOICE_INTERACTION) {if (token.windowType != TYPE_VOICE_INTERACTION) {Slog.w(TAG_WM, "Attempted to add voice interaction window with bad token "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}} else if (rootType == TYPE_WALLPAPER) {//令牌不为空,且属于壁纸if (token.windowType != TYPE_WALLPAPER) {//判断令牌类型是否为壁纸Slog.w(TAG_WM, "Attempted to add wallpaper window with bad token "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}} else if (rootType == TYPE_DREAM) {if (token.windowType != TYPE_DREAM) {Slog.w(TAG_WM, "Attempted to add Dream window with bad token "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}} else if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with bad token "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}} else if (type == TYPE_TOAST) {//令牌不为空,且属于吐司// Apps targeting SDK above N MR1 cannot arbitrary add toast windows.addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,callingUid, parentWindow);if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {Slog.w(TAG_WM, "Attempted to add a toast window with bad token "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}} else if (type == TYPE_QS_DIALOG) {if (token.windowType != TYPE_QS_DIALOG) {Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "+ attrs.token + ".  Aborting.");return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}} else if (token.asAppWindowToken() != null) {Slog.w(TAG_WM, "Non-null appWindowToken for system window of rootType=" + rootType);// It is not valid to use an app token with other system types; we will// instead make a new token for it (as if null had been passed in for the token).attrs.token = null;token = new WindowToken(this, client.asBinder(), type, false, displayContent,session.mCanAddInternalSystemWindow);}...代码省略...}
}            

上面代码主要做了两个方向的判断。
1)窗口令牌为空,结合窗口根类型判断是否需要返回异常,如果不返回最后还会帮窗口创建隐式令牌。
2)窗口令牌不为空,则会进一步结合窗口令牌的类型来判断是否需要返回异常。

6、继续往下看WindowManagerService的addWindow方法。

public class WindowManagerService extends IWindowManager.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {public int addWindow(Session session, IWindow client, int seq,LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,Rect outContentInsets, Rect outStableInsets, Rect outOutsets,DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) { ...代码省略...final WindowState win = new WindowState(this, session, client, token, parentWindow,appOp[0], seq, attrs, viewVisibility, session.mUid,session.mCanAddInternalSystemWindow);if (win.mDeathRecipient == null) {// Client has apparently died, so there is no reason to// continue.Slog.w(TAG_WM, "Adding window client " + client.asBinder()+ " that is dead, aborting.");return WindowManagerGlobal.ADD_APP_EXITING;}if (win.getDisplayContent() == null) {Slog.w(TAG_WM, "Adding window to Display that has been removed.");return WindowManagerGlobal.ADD_INVALID_DISPLAY;}final boolean hasStatusBarServicePermission =mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE)== PackageManager.PERMISSION_GRANTED;mPolicy.adjustWindowParamsLw(win, win.mAttrs, hasStatusBarServicePermission);win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));//在将弹窗添加到WindowManagerService前,做一些准备工作,具体实现类为PhoneWindowManagerres = mPolicy.prepareAddWindowLw(win, attrs);if (res != WindowManagerGlobal.ADD_OKAY) {return res;}...代码省略...}}

7、继续往下看WindowManagerService的addWindow方法。

public class WindowManagerService extends IWindowManager.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {public int addWindow(Session session, IWindow client, int seq,LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,Rect outContentInsets, Rect outStableInsets, Rect outOutsets,DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) { ...代码省略...final boolean openInputChannels = (outInputChannel != null&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);if  (openInputChannels) {win.openInputChannel(outInputChannel);}// If adding a toast requires a token for this app we always schedule hiding// toast windows to make sure they don't stick around longer then necessary.// We hide instead of remove such windows as apps aren't prepared to handle// windows being removed under them.//// If the app is older it can add toasts without a token and hence overlay// other apps. To be maximally compatible with these apps we will hide the// window after the toast timeout only if the focused window is from another// UID, otherwise we allow unlimited duration. When a UID looses focus we// schedule hiding all of its toast windows.if (type == TYPE_TOAST) {if (!getDefaultDisplayContentLocked().canAddToastWindowForUid(callingUid)) {Slog.w(TAG_WM, "Adding more than one toast window for UID at a time.");return WindowManagerGlobal.ADD_DUPLICATE_ADD;}// Make sure this happens before we moved focus as one can make the// toast focusable to force it not being hidden after the timeout.// Focusable toasts are always timed out to prevent a focused app to// show a focusable toasts while it has focus which will be kept on// the screen after the activity goes away.if (addToastWindowRequiresToken|| (attrs.flags & LayoutParams.FLAG_NOT_FOCUSABLE) == 0|| mCurrentFocus == null|| mCurrentFocus.mOwnerUid != callingUid) {mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),win.mAttrs.hideTimeoutMilliseconds);}}// From now on, no exceptions or errors allowed!res = WindowManagerGlobal.ADD_OKAY;if (mCurrentFocus == null) {mWinAddedSinceNullFocus.add(win);}if (excludeWindowTypeFromTapOutTask(type)) {displayContent.mTapExcludedWindows.add(win);}origId = Binder.clearCallingIdentity();win.attach();mWindowMap.put(client.asBinder(), win);win.initAppOpsState();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;}}...代码省略...}}            

8、继续往下看

public class WindowManagerService extends IWindowManager.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {public int addWindow(Session session, IWindow client, int seq,LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,Rect outContentInsets, Rect outStableInsets, Rect outOutsets,DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) { ...代码省略...// If the window is being added to a stack that's currently adjusted for IME,// make sure to apply the same adjust to this new window.win.applyAdjustForImeIfNeeded();if (type == TYPE_DOCK_DIVIDER) {mRoot.getDisplayContent(displayId).getDockedDividerController().setWindow(win);}final WindowStateAnimator winAnimator = win.mWinAnimator;winAnimator.mEnterAnimationPending = true;winAnimator.mEnteringAnimation = true;// Check if we need to prepare a transition for replacing window first.if (atoken != null && atoken.isVisible()&& !prepareWindowReplacementTransition(atoken)) {// If not, check if need to set up a dummy transition during display freeze// so that the unfreeze wait for the apps to draw. This might be needed if// the app is relaunching.prepareNoneTransitionForRelaunching(atoken);}final DisplayFrames displayFrames = displayContent.mDisplayFrames;// TODO: Not sure if onDisplayInfoUpdated() call is needed.final DisplayInfo displayInfo = displayContent.getDisplayInfo();displayFrames.onDisplayInfoUpdated(displayInfo,displayContent.calculateDisplayCutoutForRotation(displayInfo.rotation));final Rect taskBounds;if (atoken != null && atoken.getTask() != null) {taskBounds = mTmpRect;atoken.getTask().getBounds(mTmpRect);} else {taskBounds = null;}if (mPolicy.getLayoutHintLw(win.mAttrs, taskBounds, displayFrames, outFrame,outContentInsets, outStableInsets, outOutsets, outDisplayCutout)) {res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR;}if (mInTouchMode) {res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;}if (win.mAppToken == null || !win.mAppToken.isClientHidden()) {res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;}mInputMonitor.setUpdateInputWindowsNeededLw();boolean focusChanged = false;if (win.canReceiveKeys()) {focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,false /*updateInputWindows*/);if (focusChanged) {imMayMove = false;}}if (imMayMove) {displayContent.computeImeTarget(true /* updateImeTarget */);}// Don't do layout here, the window must call// relayout to be displayed, so we'll do it there.win.getParent().assignChildLayers();if (focusChanged) {mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);}mInputMonitor.updateInputWindowsLw(false /*force*/);if (localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addWindow: New client "+ client.asBinder() + ": window=" + win + " Callers=" + Debug.getCallers(5));if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(displayId)) {reportNewConfig = true;}}if (reportNewConfig) {sendNewConfiguration(displayId);}Binder.restoreCallingIdentity(origId);return res;}}

http://www.ppmy.cn/news/37810.html

相关文章

selenium和Firefox的安装配置

selenium和firefox的安装配置1.1、Firefox的安装1.2、Firefox驱动geckodriver的安装1.3、geckodriver环境配置两种方式1.3.1、直接添加1.3.2、手动配置1.4、python安装selenium库两种方式1.4.1、使用pip命令进行安装1.4.2、Pycharm当中安装1.1、Firefox的安装 这之前我们先安装…

最新前端面试知识点总结-2023(3w+字,长篇幅)

2023-前端面试知识点总结面试题总览javascript相关一、js 代码的常用优化手段二、es5 构造函数与继承三、new 一个对象的过程四、防抖与节流五、promise/A规范概述六、实现一个柯里函数封装七、事件队列八、微任务是哪些宏任务是哪些九、执行js代码时&#xff0c;同步任务、微任…

Kafka + Canal + MySQL 集群部署

目录 1、什么是Canal&#xff1f; canal产生的背景&#xff1a; canal工作原理主要是利用了mysql的主从复制原理&#xff1a; canal工作原理&#xff1a; 实验环境&#xff1a; 实验目的&#xff1a; 2、mysql的安装部署 mysql下载路径&#xff1a; 开启二进制日志 配置…

Python 自动化指南(繁琐工作自动化)第二版:十七、计时、安排任务和启动程序

原文&#xff1a;https://automatetheboringstuff.com/2e/chapter17/ 坐在电脑前运行程序是没问题的&#xff0c;但让程序在没有你直接监督的情况下运行也很有用。您计算机的时钟可以安排程序在某个指定的时间和日期或定期运行代码。例如&#xff0c;你的程序可以每小时抓取一个…

MATLAB 求解定积分和不定积分

本文主要介绍如何通过matlab 去求解常见的定积分和不定积分的结果&#xff0c;使用matlab 内置函数 int。 语法&#xff1a; Fint(表达式&#xff0c;变量&#xff0c;变量上下限) 目录 例子1 单变量不定积分 例子2 多变量不定积分 例子3 单变量定积分 例子4 定积分近似求…

Linux SSH失效的几种情况以及排查方法

公司有个项目是用三台Linux服务器的&#xff0c;在第一台服务器上使用shell脚本同时部署至三台服务器 突然最近有个生产环境SSH不好用了&#xff0c;经过仔细排查才得以解决 SSH可能会在以下情况下失效&#xff1a; 1. SSH服务未启动 检查SSH服务是否启动&#xff1a;system…

【项目】Java API站内搜索引擎

1.项目目标2.项目过程2.1预处理2.2构建索引2.2.1正排索引查询添加2.2.2倒排索引查询添加2.2.3保存到本地2.2.4从本地加载索引2.2.5性能优化多线程解决线程安全问题首次制作索引比较慢缓存2.3搜索模块2.3.1划分关键词加载索引、停用词分词2.3.2触发文档2.3.3权重排序权重合并降序…

技术宅小伙:ChatGPT的编程能力到底有多厉害?

欢迎大家光临技术宅小伙的博客&#xff01; 有特别多朋友问我 如何给自己制定一份 行之有效的编程学习计划 我最近发现CHATGPT在这方面特别棒 所以今天跟大家简单介绍一下 如何用CHATGPT根据我们自身的特点 帮我们制定一份行之有效的学习规划 …