北京做网站价格,好的产品怎么推广语言,濮阳网络直播,南昌网站开发Android14 WMS-窗口添加流程(一)-Client端-CSDN博客
本文接着上文Android14 WMS-窗口添加流程(一)-Client端往下讲。也就是WindowManagerService#addWindow流程。
目录
一. WindowManagerService#addWindow
标志1#xff1a;mPolicy.checkAddPermission
标志…Android14 WMS-窗口添加流程(一)-Client端-CSDN博客
本文接着上文Android14 WMS-窗口添加流程(一)-Client端往下讲。也就是WindowManagerService#addWindow流程。
目录
一. WindowManagerService#addWindow
标志1mPolicy.checkAddPermission
标志2getDisplayContentOrCreate
标志3 mWindowMap
二窗口类型检查
三新建WindowToken
标志1 WindowToken
四 新建WindowState 五adjustWindowParamsLw 六窗口ADD_OKAY后续流程 整个流程如下 一. WindowManagerService#addWindow
http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java#1431 public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,int displayId, int requestUserId, InsetsType int requestedVisibleTypes,InputChannel outInputChannel, InsetsState outInsetsState,InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,float[] outSizeCompatScale) {outActiveControls.set(null);int[] appOp new int[1];
//权限检查final boolean isRoundedCornerOverlay (attrs.privateFlags PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) ! 0;
//标志1int res mPolicy.checkAddPermission(attrs.type, isRoundedCornerOverlay, attrs.packageName,appOp);if (res ! ADD_OKAY) {return res;}
//父windowWindowState parentWindow null;
//发起者Uidfinal int callingUid Binder.getCallingUid();
//发起者Pidfinal int callingPid Binder.getCallingPid();final long origId Binder.clearCallingIdentity();
//窗口类型final int type attrs.type;synchronized (mGlobalLock) {if (!mDisplayReady) {throw new IllegalStateException(Display has not been initialialized);}
//一个DisplayContent对应一个绘制屏幕
//标志2final DisplayContent displayContent getDisplayContentOrCreate(displayId, attrs.token);if (displayContent null) {ProtoLog.w(WM_ERROR, Attempted to add window to a display that does not exist: %d. Aborting., displayId);return WindowManagerGlobal.ADD_INVALID_DISPLAY;}if (!displayContent.hasAccess(session.mUid)) {ProtoLog.w(WM_ERROR,Attempted to add window to a display for which the application does not have access: %d. Aborting.,displayContent.getDisplayId());return WindowManagerGlobal.ADD_INVALID_DISPLAY;}
//是否已经添加对应的窗口 去重判断
//标志3if (mWindowMap.containsKey(client.asBinder())) {ProtoLog.w(WM_ERROR, Window %s is already added, client);return WindowManagerGlobal.ADD_DUPLICATE_ADD;}由于此方法太长所以我会分开去讲
标志1mPolicy.checkAddPermission
mPolicy定义如下如果此方法返回ADD_OKAY则代码无权限问题否则直接返回。 WindowManagerPolicy mPolicy;
------------------------------------------int res mPolicy.checkAddPermission(attrs.type, isRoundedCornerOverlay, attrs.packageName, appOp);if (res ! ADD_OKAY) {return res;} WindowManagerPolicy.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java /**当add window的时候检查权限* Check permissions when adding a window.** param type The window type--窗口类型* param isRoundedCornerOverlay {code true} to indicate the adding window is* round corner overlay. 指示要add的窗口为圆角叠加层。* param packageName package name 包名* param outAppOp First element will be filled with the app op corresponding to this window, or OP_NONE.第一个元素将填充与此窗口对应的应用操作或OP_NONE。** return {link WindowManagerGlobal#ADD_OKAY} if the add can proceed;* else an error code, usually* {link WindowManagerGlobal#ADD_PERMISSION_DENIED}, to abort the add.*//返回是否有权限添加有则返回ADD_OKAY* see WindowManager.LayoutParams#PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY*/int checkAddPermission(int type, boolean isRoundedCornerOverlay, String packageName, int[] outAppOp);这里只是声明没有实现具体实现如下
PhoneWindowManager.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java public int checkAddPermission(int type, boolean isRoundedCornerOverlay, String packageName,int[] outAppOp) {
//如果是圆角覆盖并且无PERMISSION_GRANTED权限也无法添加windowif (isRoundedCornerOverlay mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW)! PERMISSION_GRANTED) {return ADD_PERMISSION_DENIED;}outAppOp[0] AppOpsManager.OP_NONE;
//如果窗口类型不在系统划分的三大窗口范围内则返回不合法的type--ADD_INVALID_TYPEif (!((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;}
//如果窗口类型不是系统窗口类型比如是APP窗口类型或者是子窗口类型系统最大窗口类型为LAST_SYSTEM_WINDOW则可以添加返回ADD_OKAYif (type FIRST_SYSTEM_WINDOW || type LAST_SYSTEM_WINDOW) {// Window manager will make sure these are okay.return ADD_OKAY;}
//如果窗口类型不是alert window alert window有好几种可以查看这个方法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_INPUT_METHOD:case TYPE_WALLPAPER:case TYPE_PRESENTATION:case TYPE_PRIVATE_PRESENTATION:case TYPE_VOICE_INTERACTION:case TYPE_ACCESSIBILITY_OVERLAY:case TYPE_QS_DIALOG:case TYPE_NAVIGATION_BAR_PANEL:// 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 draw
//如果是系统进程则直接允许if (UserHandle.getAppId(callingUid) Process.SYSTEM_UID) {return ADD_OKAY;}...}
标志2getDisplayContentOrCreate final DisplayContent displayContent getDisplayContentOrCreate(displayId, attrs.token); 此方法定义如下其作用是Get existing {link DisplayContent} or create a new one if the display is registered in DisplayManager.即“获取现有的DisplayContent如果display已在 DisplayManager 中注册则创建一个新DisplayContent”.
仅当尚未创建与刚刚添加到 DisplayManager 的display相对应的DisplayContent时才应使用此选项。这通常意味着此方法的调用是从 Activity 或窗口管理器外部启动的。 /*** Get existing {link DisplayContent} or create a new one if the display is registered in* DisplayManager.** NOTE: This should only be used in cases when there is a chance that a {link DisplayContent}* that corresponds to a display just added to DisplayManager has not yet been created. This* usually means that the call of this method was initiated from outside of Activity or Window* Manager. In most cases the regular getter should be used.* param displayId The preferred display Id.* param token The window token associated with the window we are trying to get display for.* if not null then the display of the window token will be returned. Set to null* is there isnt an a token associated with the request.* see RootWindowContainer#getDisplayContent(int)*/private DisplayContent getDisplayContentOrCreate(int displayId, IBinder token) {if (token ! null) {
//WM中相关联的窗口集合
//tag1final WindowToken wToken mRoot.getWindowToken(token);if (wToken ! null) {
//tag2return wToken.getDisplayContent();}}
//tag3return mRoot.getDisplayContentOrCreate(displayId);}
这块涉及到Container我们来看看继承关系 设备的Root WindowContainer一个设备只有一个RootWindowContainer
class RootWindowContainer extends WindowContainerDisplayContentimplements DisplayManager.DisplayListener {一个设备只有一个RootWindowContainer, 因为它的赋值是在WMS的实例化中,WMS实例在全局只有一个是从SystemServer中发起的。 private WindowManagerService(Context context, InputManagerService inputManager, boolean showBootMsgs, WindowManagerPolicy policy, ActivityTaskManagerService atm,DisplayWindowSettingsProvider displayWindowSettingsProvider, SupplierSurfaceControl.Transaction transactionFactory, FunctionSurfaceSession, SurfaceControl.Builder surfaceControlFactory) {
...mRoot new RootWindowContainer(this); ----------------------------------------------------------------------------------------------------------- 一系列相关window的集合
通常这是一个AppWindowToken(AppWindowToken就是activity)它是用于显示窗口的 Activity的句柄。
这个主要用于表示窗口的令牌(Token)信息主要负责管理窗口的一些属性和行为通过WindowTokenWMS可以对窗口进行布局层级排序焦点管理输入事件分发等操作。
class WindowToken extends WindowContainerWindowState { 此外ActivityRecord继承WindowToken一个ActivityRecord代表一个activity
final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener { ----------------------------------------------------------------------------------------------------------- WindowContainer作为窗口层级结构中的基本单元负责承载一个窗口的所有信息和状态。每个窗口容器都对应一个窗口并包含了窗口的配置信息、绘制信息、动画状态等。
WindowContainer还提供了与窗口相关的操作接口如设置窗口属性、绘制窗口内容等。
在源码层面WindowContainer的实现通常涉及到多个类和接口。
例如WindowContainer类可能包含了一些与窗口容器相关的属性和方法如窗口的位置、大小、背景色等。此外WindowContainer还可能与其他组件进行交互如与SurfaceFlinger进行渲染交互与InputManager进行输入事件处理等。
class WindowContainerE extends WindowContainer extends ConfigurationContainerEimplements ComparableWindowContainer, Animatable, SurfaceFreezer.Freezable, InsetsControlTarget {
...
一系列子级window container集合。此集合按 z 顺序排列因为子项显示在屏幕上最上面的window container位于列表的尾部。
mChildren.add和mChildren.remove操作都在WindowContainer.java中protected final WindowListE mChildren new WindowListE();WindowList介绍如下 一个 ArrayList存储WindowContainer中的子window container
class WindowListE extends ArrayListE {
添加到集合首位void addFirst(E e) {add(0, e);}
选择最后一位E peekLast() {return size() 0 ? get(size() - 1) : null;}
选择第一位E peekFirst() {return size() 0 ? get(0) : null;}
} ----------------------------------------------------------------------------------------------------------- 包含具有重写配置并按层次结构组织的类的通用逻辑。
public abstract class ConfigurationContainerE extends ConfigurationContainer {回归正题来看看tag1处mRoot.getWindowToken(token); 刚刚已经讲过mChildren是一系列子级window container集合那我们通过binder对此集合遍历找到binder对应的windowtoken然后返回。 /** Returns the window token for the input binder if it exist in the system.*/WindowToken getWindowToken(IBinder binder) {for (int i mChildren.size() - 1; i 0; --i) {final DisplayContent dc mChildren.get(i);final WindowToken wtoken dc.getWindowToken(binder);if (wtoken ! null) {return wtoken;}}return null;} 用于跟踪特定 Display 的 WindowStates 和其他相关内容的 辅助类。
DisplayContent 用于管理屏幕一块屏幕对应一个 DisplayContent 对象虽然手机只有一个显示屏但是可以创建多个 DisplayContent 对象
class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.DisplayContentInfo { 标志3 mWindowMap
mWindowMap保存了每个WindowState和客户端窗口的映射关系客户端应用请求窗口操作时通过mWindowMap查询到对应的WindowState /** Mapping from an IWindow IBinder to the servers Window object. */final HashMapIBinder, WindowState mWindowMap new HashMap(); 二窗口类型检查
如果是子窗口类型if (type FIRST_SUB_WINDOW type LAST_SUB_WINDOW) {
先找到它的父窗口子窗口需要依附在父窗口上如果父窗口为null则返回ADD_BAD_SUBWINDOW_TOKENparentWindow windowForClientLocked(null, attrs.token, false);if (parentWindow null) {ProtoLog.w(WM_ERROR, Attempted to add window with token that is not a window: %s. Aborting., attrs.token);return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;}
如果父窗口也是一个子窗口也直接返回ADD_BAD_SUBWINDOW_TOKENif (parentWindow.mAttrs.type FIRST_SUB_WINDOW parentWindow.mAttrs.type LAST_SUB_WINDOW) {ProtoLog.w(WM_ERROR, Attempted to add window with token that is a sub-window: %s. Aborting., attrs.token);return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;}}
如果窗口是保密类型但displayContent不是保密类型则返回ADD_PERMISSION_DENIEDif (type TYPE_PRIVATE_PRESENTATION !displayContent.isPrivate()) {ProtoLog.w(WM_ERROR,Attempted to add private presentation window to a non-private display. Aborting.);return WindowManagerGlobal.ADD_PERMISSION_DENIED;}
如果窗口是保密类型但displayContent的屏幕是公开演示显示器返回ADD_INVALID_DISPLAYif (type TYPE_PRESENTATION !displayContent.getDisplay().isPublicPresentation()) {ProtoLog.w(WM_ERROR,Attempted to add presentation window to a non-suitable display. Aborting.);return WindowManagerGlobal.ADD_INVALID_DISPLAY;}三新建WindowToken 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.
子窗口使用现有的父窗口令牌因为它们与父窗口使用相同的令牌因此我们可以对它们应用相同的策略。
根据客户端传来的token获取windowTokenWindowToken token displayContent.getWindowToken(hasParent ? parentWindow.mAttrs.token : attrs.token);// If this is a child window, we want to apply the same type checking rules as the// parent window type.
如果这是一个子窗口我们希望应用与父窗口类型相同的类型检查规则。final int rootType hasParent ? parentWindow.mAttrs.type : type;boolean addToastWindowRequiresToken false;final IBinder windowContextToken attrs.mWindowContextToken;if (token null) {如果token为空if (!unprivilegedAppCanCreateTokenWith(parentWindow, callingUid, type,rootType, attrs.token, attrs.packageName)) {return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}if (hasParent) {如果有父级window// Use existing parent window token for child windows.token parentWindow.mToken;则直接用父级token给所有的子windows} else if (mWindowContextListenerController.hasListener(windowContextToken)) {// Respect the window context token if the user provided it.
如果用户提供了窗口上下文令牌则用windowContextTokenfinal IBinder binder attrs.token ! null ? attrs.token : windowContextToken;final Bundle options mWindowContextListenerController.getOptions(windowContextToken);token new WindowToken.Builder(this, binder, type).setDisplayContent(displayContent).setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow).setRoundedCornerOverlay(isRoundedCornerOverlay).setFromClientToken(true).setOptions(options).build();} else {final IBinder binder attrs.token ! null ? attrs.token : client.asBinder();token new WindowToken.Builder(this, binder, type).setDisplayContent(displayContent).setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow).setRoundedCornerOverlay(isRoundedCornerOverlay).build();}
如果是APP类型窗口} else if (rootType FIRST_APPLICATION_WINDOW rootType LAST_APPLICATION_WINDOW) {
通过token获取ActivityRecordactivity token.asActivityRecord();if (activity null) {ProtoLog.w(WM_ERROR, Attempted to add window with non-application token .%s Aborting., token);return WindowManagerGlobal.ADD_NOT_APP_TOKEN;} else if (activity.getParent() null) {ProtoLog.w(WM_ERROR, Attempted to add window with exiting application token .%s Aborting., token);return WindowManagerGlobal.ADD_APP_EXITING;
窗口类型为starting window} else if (type TYPE_APPLICATION_STARTING) {if (activity.mStartingWindow ! null) {ProtoLog.w(WM_ERROR, Attempted to add starting window to token with already existing starting window);return WindowManagerGlobal.ADD_DUPLICATE_ADD;}if (activity.mStartingData null) {ProtoLog.w(WM_ERROR, Attempted to add starting window to token but already cleaned);return WindowManagerGlobal.ADD_DUPLICATE_ADD;}}
窗口类型为input window} else if (rootType TYPE_INPUT_METHOD) {if (token.windowType ! TYPE_INPUT_METHOD) {ProtoLog.w(WM_ERROR, Attempted to add input method window with bad token %s. Aborting., attrs.token);return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}
窗口类型为voice window} else if (rootType TYPE_VOICE_INTERACTION) {if (token.windowType ! TYPE_VOICE_INTERACTION) {ProtoLog.w(WM_ERROR, Attempted to add voice interaction window with bad token %s. Aborting., attrs.token);return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}
窗口类型为壁纸} else if (rootType TYPE_WALLPAPER) {if (token.windowType ! TYPE_WALLPAPER) {ProtoLog.w(WM_ERROR, Attempted to add wallpaper window with bad token %s. Aborting., attrs.token);return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}
窗口类型为辅助功能 OVERLAY} else if (rootType TYPE_ACCESSIBILITY_OVERLAY) {if (token.windowType ! TYPE_ACCESSIBILITY_OVERLAY) {ProtoLog.w(WM_ERROR,Attempted to add Accessibility overlay window with bad token %s. Aborting., attrs.token);return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}
窗口类型为Toast类型} 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) {ProtoLog.w(WM_ERROR, Attempted to add a toast window with bad token %s. Aborting., attrs.token);return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}} else if (type TYPE_QS_DIALOG) {if (token.windowType ! TYPE_QS_DIALOG) {ProtoLog.w(WM_ERROR, Attempted to add QS dialog window with bad token %s. Aborting., attrs.token);return WindowManagerGlobal.ADD_BAD_APP_TOKEN;}
通过token获取到的ActivityRecord不为空} else if (token.asActivityRecord() ! null) {ProtoLog.w(WM_ERROR, Non-null activity for system window of rootType%d,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).
将应用令牌用于其他系统类型是无效的;
相反我们将为它创建一个新的令牌就好像已经为令牌传入了 null 一样。attrs.token null;
创建WindowToken
标志1token new WindowToken.Builder(this, client.asBinder(), type).setDisplayContent(displayContent).setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow).build();}
标志1 WindowToken
通常这是一个AppWindowToken(AppWindowToken就是activity)它是用于显示窗口的 Activity的句柄。 这个主要用于表示窗口的令牌(Token)信息主要负责管理窗口的一些属性和行为通过WindowTokenWMS可以对窗口进行布局层级排序焦点管理输入事件分发等操作。 token new WindowToken.Builder(this, client.asBinder(), type) .setDisplayContent(displayContent) .setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow) .build(); //build()就能创建出来WindowToken对象 class WindowToken extends WindowContainerWindowState {protected WindowToken(WindowManagerService service, IBinder _token, int type,
boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens) {this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens,
false /* roundedCornerOverlay */, false /* fromClientToken */, null /* options */);}protected WindowToken(WindowManagerService service, IBinder _token, int type,
boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens,
boolean roundedCornerOverlay, boolean fromClientToken, Nullable Bundle options) {super(service);token _token;windowType type;mOptions options;mPersistOnEmpty persistOnEmpty;mOwnerCanManageAppTokens ownerCanManageAppTokens;mRoundedCornerOverlay roundedCornerOverlay;mFromClientToken fromClientToken;if (dc ! null) {dc.addWindowToken(token, this);}}---------------------------------------------static class Builder {private final WindowManagerService mService;private final IBinder mToken;WindowTypeprivate final int mType;private boolean mPersistOnEmpty;private DisplayContent mDisplayContent;private boolean mOwnerCanManageAppTokens;Nullableprivate Bundle mOptions;Builder(WindowManagerService service, IBinder token, int type) {mService service;mToken token;mType type;}/** Sets the {link DisplayContent} to be associated. */Builder setDisplayContent(DisplayContent dc) {mDisplayContent dc;return this;}/** see WindowToken#mOwnerCanManageAppTokens */Builder setOwnerCanManageAppTokens(boolean ownerCanManageAppTokens) {mOwnerCanManageAppTokens ownerCanManageAppTokens;return this;}WindowToken build() {return new WindowToken(mService, mToken, mType, mPersistOnEmpty, mDisplayContent, mOwnerCanManageAppTokens, mRoundedCornerOverlay, mFromClientToken, mOptions);}}四 新建WindowState
创建WindowStatefinal WindowState win new WindowState(this, session, client, token, parentWindow,appOp[0], attrs, viewVisibility, session.mUid, userId,session.mCanAddInternalSystemWindow);if (win.mDeathRecipient null) {// Client has apparently died, so there is no reason to// continue.ProtoLog.w(WM_ERROR, Adding window client %s that is dead, aborting., client.asBinder());return WindowManagerGlobal.ADD_APP_EXITING;}
WindowState对应的DisplayContent为空则没有对应的屏幕去显示window所以报错if (win.getDisplayContent() null) {ProtoLog.w(WM_ERROR, Adding window to Display that has been removed.);return WindowManagerGlobal.ADD_INVALID_DISPLAY;}
WindowState表示一个窗口的所有属性一个WindowState对应一个窗口借用一张图来表示也就解释了为什么WindowToken是一系列Window的集合的容器了。
WindowToken--Container of a set of related windows in the window manager
/** A window in the window manager. */
class WindowState extends WindowContainerWindowState implements WindowManagerPolicy.WindowState,InsetsControlTarget, InputTarget { 五adjustWindowParamsLw
获取DisplayPolicyfinal DisplayPolicy displayPolicy displayContent.getDisplayPolicy();
调整窗口参数displayPolicy.adjustWindowParamsLw(win, win.mAttrs);attrs.flags sanitizeFlagSlippery(attrs.flags, win.getName(), callingUid, callingPid);attrs.inputFeatures sanitizeSpyWindow(attrs.inputFeatures, win.getName(), callingUid,callingPid);win.setRequestedVisibleTypes(requestedVisibleTypes);
检查窗口是否可以添加至系统主要是检查权限相关res displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);if (res ! ADD_OKAY) {return res;}
/**提供要显示的UI的基本行为和状态的策略。* The policy that provides the basic behaviors and states of a display to show UI.*/
public class DisplayPolicy {
在DisplayPolicy实例化中有关于手势相关的比如下拉状态栏左滑返回这种。
DisplayPolicy还可以调整布局相关
adjustWindowParamsLw作用根据客户端的布局参数调整布局。 允许策略执行某些操作例如确保特定类型的窗口不能采用输入焦点。 public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs) {switch (attrs.type) {case TYPE_SYSTEM_OVERLAY:case TYPE_SECURE_SYSTEM_OVERLAY:
如果窗口类型是这个则给窗口flag添加如下参数// These types of windows cant receive input events.attrs.flags | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;attrs.flags ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;break;case TYPE_WALLPAPER:
如果是壁纸类型则设置让窗口总是可以扩展到刘海区域中// Dreams and wallpapers dont have an app window token and can thus not be// letterboxed. Hence always let them extend under the cutout.attrs.layoutInDisplayCutoutMode LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;break;case TYPE_TOAST:
...attrs.flags | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;break;case TYPE_BASE_APPLICATION:
...break;}
...}layoutInDisplayCutoutMode的默认值是LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT。 layoutInDisplayCutoutModeValue含义LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT0这是默认行为在竖屏模式下内容会呈现到刘海区域中但在横屏模式下内容会显示黑边。LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES1在竖屏模式和横屏模式下内容都会呈现到刘海区域中LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER2内容从不呈现到刘海区域中LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS3窗口总是可以扩展到刘海区域中 六窗口ADD_OKAY后续流程 final boolean openInputChannels (outInputChannel ! null (attrs.inputFeatures INPUT_FEATURE_NO_INPUT_CHANNEL) 0);if (openInputChannels) {
打开input channelwin.openInputChannel(outInputChannel);}
...// From now on, no exceptions or errors allowed!
能走到这里那就说明这个窗口可以添加没有问题res ADD_OKAY;
请求创建一个BLAST (Buffer as LayerState)层的标志。
如果没有指定客户端将接收一个BufferQueue层。if (mUseBLAST) {res | WindowManagerGlobal.ADD_FLAG_USE_BLAST;}
...
// void attach() {
// if (DEBUG) Slog.v(TAG, Attaching this token mToken);
// mSession.windowAddedLocked();
// }
将这个windowstate即这个窗口更新到Session中的 mNumWindow中win.attach();
mWindowMap更新前面有讲过mWindowMap作用
保存 IWindow IBinder和windowstate的匹配
//Mapping from an IWindow IBinder to the servers Window object.mWindowMap.put(client.asBinder(), win);win.initAppOpsState();
当前window对应的token添加windowstatewin.mToken.addWindow(win);
策略更新window及其对应的窗口属性displayPolicy.addWindowLw(win, attrs);displayPolicy.setDropInputModePolicy(win, win.mAttrs);if (type TYPE_APPLICATION_STARTING activity ! null) {
activityrecord添加starting window窗口activity.attachStartingWindow(win);ProtoLog.v(WM_DEBUG_STARTING_WINDOW, addWindow: %s startingWindow%s,activity, win);} else if (type TYPE_INPUT_METHOD// IME window is always touchable.// Ignore non-touchable windows e.g. Stylus InkWindow.java. (win.getAttrs().flags FLAG_NOT_TOUCHABLE) 0) {
如果是输入法且可触摸则给这个display设置输入法displayContent.setInputMethodWindowLocked(win);imMayMove false;} else if (type TYPE_INPUT_METHOD_DIALOG) {
如果是输入法dialog则计算输入法目标displayContent.computeImeTarget(true /* updateImeTarget */);imMayMove false;
...
窗口可以接受输入事件if (win.canReceiveKeys()) {
更新焦点窗口focusChanged updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,false /*updateInputWindows*/);if (focusChanged) {imMayMove false;}}
...// Dont do layout here, the window must call// relayout to be displayed, so well do it there.win.getParent().assignChildLayers();
窗口焦点更新了所以当前输入焦点窗口也要重新设置if (focusChanged) {displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus,false /*updateInputWindows*/);}
更新输入窗口displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
...// This window doesnt have a frame yet. Dont let this window cause the insets change.displayContent.getInsetsStateController().updateAboveInsetsState(false /* notifyInsetsChanged */);outInsetsState.set(win.getCompatInsetsState(), true /* copySources */);getInsetsSourceControls(win, outActiveControls);
...return res;} 文章转载自: http://www.morning.tpyrn.cn.gov.cn.tpyrn.cn http://www.morning.fxwkl.cn.gov.cn.fxwkl.cn http://www.morning.gmwdl.cn.gov.cn.gmwdl.cn http://www.morning.jtwck.cn.gov.cn.jtwck.cn http://www.morning.pmdzd.cn.gov.cn.pmdzd.cn http://www.morning.ylph.cn.gov.cn.ylph.cn http://www.morning.ztcxx.com.gov.cn.ztcxx.com http://www.morning.hqllj.cn.gov.cn.hqllj.cn http://www.morning.tyjp.cn.gov.cn.tyjp.cn http://www.morning.mhnb.cn.gov.cn.mhnb.cn http://www.morning.dpplr.cn.gov.cn.dpplr.cn http://www.morning.rfgc.cn.gov.cn.rfgc.cn http://www.morning.bfybb.cn.gov.cn.bfybb.cn http://www.morning.gjtdp.cn.gov.cn.gjtdp.cn http://www.morning.yqlrq.cn.gov.cn.yqlrq.cn http://www.morning.rhsr.cn.gov.cn.rhsr.cn http://www.morning.xzsqb.cn.gov.cn.xzsqb.cn http://www.morning.qggxt.cn.gov.cn.qggxt.cn http://www.morning.qyqdz.cn.gov.cn.qyqdz.cn http://www.morning.wwnb.cn.gov.cn.wwnb.cn http://www.morning.qlrwf.cn.gov.cn.qlrwf.cn http://www.morning.npmx.cn.gov.cn.npmx.cn http://www.morning.prprz.cn.gov.cn.prprz.cn http://www.morning.smnxr.cn.gov.cn.smnxr.cn http://www.morning.qzzmc.cn.gov.cn.qzzmc.cn http://www.morning.cpctr.cn.gov.cn.cpctr.cn http://www.morning.spdyl.cn.gov.cn.spdyl.cn http://www.morning.frsxt.cn.gov.cn.frsxt.cn http://www.morning.ppbqz.cn.gov.cn.ppbqz.cn http://www.morning.pqnps.cn.gov.cn.pqnps.cn http://www.morning.lzsxp.cn.gov.cn.lzsxp.cn http://www.morning.wqrdx.cn.gov.cn.wqrdx.cn http://www.morning.drndl.cn.gov.cn.drndl.cn http://www.morning.bnrnb.cn.gov.cn.bnrnb.cn http://www.morning.fnfxp.cn.gov.cn.fnfxp.cn http://www.morning.btnmj.cn.gov.cn.btnmj.cn http://www.morning.nlbhj.cn.gov.cn.nlbhj.cn http://www.morning.qynnw.cn.gov.cn.qynnw.cn http://www.morning.snnkt.cn.gov.cn.snnkt.cn http://www.morning.bxfy.cn.gov.cn.bxfy.cn http://www.morning.mxhgy.cn.gov.cn.mxhgy.cn http://www.morning.xgzwj.cn.gov.cn.xgzwj.cn http://www.morning.kcypc.cn.gov.cn.kcypc.cn http://www.morning.pmbcr.cn.gov.cn.pmbcr.cn http://www.morning.dkbsq.cn.gov.cn.dkbsq.cn http://www.morning.cnwpb.cn.gov.cn.cnwpb.cn http://www.morning.qlkzl.cn.gov.cn.qlkzl.cn http://www.morning.langlaitech.cn.gov.cn.langlaitech.cn http://www.morning.kpwcx.cn.gov.cn.kpwcx.cn http://www.morning.qcwrm.cn.gov.cn.qcwrm.cn http://www.morning.hxycm.cn.gov.cn.hxycm.cn http://www.morning.pljxz.cn.gov.cn.pljxz.cn http://www.morning.sqxr.cn.gov.cn.sqxr.cn http://www.morning.gqksd.cn.gov.cn.gqksd.cn http://www.morning.dpzcc.cn.gov.cn.dpzcc.cn http://www.morning.qgwpx.cn.gov.cn.qgwpx.cn http://www.morning.cknws.cn.gov.cn.cknws.cn http://www.morning.nxkyr.cn.gov.cn.nxkyr.cn http://www.morning.xcnwf.cn.gov.cn.xcnwf.cn http://www.morning.ncrk.cn.gov.cn.ncrk.cn http://www.morning.ysgnb.cn.gov.cn.ysgnb.cn http://www.morning.wzyfk.cn.gov.cn.wzyfk.cn http://www.morning.wlfxn.cn.gov.cn.wlfxn.cn http://www.morning.jbgzy.cn.gov.cn.jbgzy.cn http://www.morning.hfxks.cn.gov.cn.hfxks.cn http://www.morning.lpsjs.com.gov.cn.lpsjs.com http://www.morning.ktmnq.cn.gov.cn.ktmnq.cn http://www.morning.mrfnj.cn.gov.cn.mrfnj.cn http://www.morning.kxqfz.cn.gov.cn.kxqfz.cn http://www.morning.drhnj.cn.gov.cn.drhnj.cn http://www.morning.qytpt.cn.gov.cn.qytpt.cn http://www.morning.lhrxq.cn.gov.cn.lhrxq.cn http://www.morning.jwrcz.cn.gov.cn.jwrcz.cn http://www.morning.bsqkt.cn.gov.cn.bsqkt.cn http://www.morning.pwxkn.cn.gov.cn.pwxkn.cn http://www.morning.gqtzb.cn.gov.cn.gqtzb.cn http://www.morning.njddz.cn.gov.cn.njddz.cn http://www.morning.qmbpy.cn.gov.cn.qmbpy.cn http://www.morning.shuangxizhongxin.cn.gov.cn.shuangxizhongxin.cn http://www.morning.wnnts.cn.gov.cn.wnnts.cn