WMS 窗口属性
- 1、窗口类型与层级
- 1.1 Application Window普通应用程序窗口
- 1.2 Sub Window子窗口
- 1.3 System Window系统窗口
 
- 2、层级值与窗口类型
- 2.1 WindowState
- 2.2 WindowManagerPolicy 窗口管理的策略机制
- 2.3 WindowToken句柄
 
- 3、窗口属性 LayoutParams
Activity的预览窗口StartingWindow添加
 Activity窗口的添加过程
 WMS:系统窗口添加过程
 android12-release
1、窗口类型与层级
Android中的“窗口”类型有很多,一般可统一划分三大类:
Application Window、System Window和Sub Window。
frameworks/base/core/java/android/view/WindowManager.java # android.view.WindowManager.LayoutParams
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java
Application Window窗口类型范围:1-99
System Window窗口类型范围:1000-1999
Sub Window窗口类型范围:2000-2999
1.1 Application Window普通应用程序窗口
应用程序窗口类型 Type 从FIRST_Application_WINDOW到LAST_Application_WINDOW,是普通的顶级应用程序窗口。对于这些类型的窗口,
token必须设置为它们所属活动的token。
| 窗口类型 Type | 描述 | 
|---|---|
| FIRST_APPLICATION_WINDOW = 1 | 表示普通应用程序窗口的窗口类型的开始。 | 
| TYPE_BASE_APPLICATION = 1 | 窗口类型:作为整个应用的“基础”窗口的应用窗口;所有其他应用程序窗口将出现在其顶部。在多用户系统中,仅在拥有用户的窗口中显示。 | 
| TYPE_APPLICATION = 2 | 窗口类型:普通应用窗口。令牌必须是标识窗口所属对象的活动令牌。在多用户系统中,仅在拥有用户的窗口中显示。 | 
| TYPE_APPLICATION_STARTING = 3 | 窗口类型:应用程序启动时显示的特殊应用程序窗口。不供应用程序本身使用;系统使用它来显示某些内容,直到应用程序可以显示自己的窗口。在多用户系统中,显示在所有用户的窗口中。 | 
| TYPE_DRAWN_APPLICATION = 4 | 窗口类型:TYPE_APPLICATION的变体,可确保窗口管理器在显示应用程序之前等待绘制此窗口。在多用户系统中,仅在拥有用户的窗口中显示。 | 
| LAST_APPLICATION_WINDOW = 99 | 应用程序窗口类型的最大值。 | 
窗口属性(LayoutParams)中Type设置:
frameworks/base/core/java/android/app/ActivityThread.java
handleResumeActivity():l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
1.2 Sub Window子窗口
子窗口类型 Type 从FIRST_Sub_WINDOW到LAST_Sub_WINDOW,与另一个顶级窗口相关联。对于这些类型的窗口,
token必须是它所附加的窗口的token。
| 窗口类型 Type | 描述 | 
|---|---|
| FIRST_SUB_WINDOW = 1000 | 子窗口类型的开始。这些窗口的 token必须设置为它们附加到的窗口。这些类型的窗口按 Z 顺序保留在其附加窗口旁边,其坐标空间相对于其附加窗口。 | 
| TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW | 窗口类型:应用程序窗口顶部的面板。这些窗口显示在附加窗口的顶部。 | 
| TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1 | 窗口类型:用于显示媒体(如视频)的窗口。这些窗口显示在附加的窗口后面。 | 
| TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2 | 窗口类型:应用程序窗口顶部的子面板。这些窗口显示在其附加窗口和任何 TYPE_APPLICATION_PANEL面板的顶部。 | 
| TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3 | 窗口类型:与 TYPE_APPLICATION_PANEL类似,但窗口的布局作为顶级窗口的布局发生,而不是作为其容器的子窗口。 | 
| TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4 | 窗口类型:用于在媒体窗口顶部显示叠加层的窗口。这些窗口显示在 TYPE_APPLICATION_MEDIA和应用程序窗口之间。它们应该是半透明的才能有用。这是一个丑陋的大黑客,所以:@hide | 
| TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5 | 窗口类型:应用程序窗口顶部的上方子面板及其子面板窗口。这些窗口显示在它们附加的窗口和任何 TYPE_APPLICATION_SUB_PANEL面板的顶部。 | 
| LAST_SUB_WINDOW = 1999 | 子窗口类型的最大值。 | 
1.3 System Window系统窗口
系统窗口类型 Type 从FIRST_System_WINDOW到LAST_System_WINDEW,是系统用于特定目的的特殊类型的窗口。它们通常不应被应用程序使用,并且需要获得特殊许可才能使用。
| 窗口类型 Type | 描述 | 
|---|---|
| FIRST_SYSTEM_WINDOW = 2000 | 系统特定的窗口类型的开始。这些通常不是由应用程序创建的。 | 
| TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW | 窗口类型: 状态栏。只能有一个状态栏窗口;它放置在屏幕顶部,所有其他窗口都向下移动,因此它们位于屏幕下方。在多用户系统中,显示在所有用户的窗口中。 | 
| TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1 | 窗口类型: 搜索栏。只能有一个搜索栏窗口;它位于屏幕顶部。在多用户系统中,显示在所有用户的窗口中。 | 
| TYPE_PHONE = FIRST_SYSTEM_WINDOW+2 | 窗口类型: 电话。这些是提供用户与电话交互(特别是传入呼叫)的非应用程序窗口。这些窗口通常放置在所有应用程序的上方,但位于状态栏后面。在多用户系统中,显示在所有用户的窗口中。已弃用非系统应用。请改用TYPE_APPLICATION_OVERLAY。 | 
| TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3 | 窗口类型: 系统窗口,如低电量报警。这些窗口始终位于应用程序窗口的顶部。在多用户系统中,仅在拥有用户的窗口中显示。已弃用非系统应用。请改用TYPE_APPLICATION_OVERLAY。 | 
| TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4 | 窗口类型: 键盘锁窗口。在多用户系统中,显示在所有用户的窗口中。 | 
| TYPE_TOAST = FIRST_SYSTEM_WINDOW+5 | 窗口类型: 瞬态通知。在多用户系统中,仅在拥有用户的窗口中显示。已弃用非系统应用。请改用TYPE_APPLICATION_OVERLAY。 | 
| TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6 | 窗口类型: 系统覆盖窗口,需要显示在其他所有窗口之上。这些窗口不得采用输入焦点,否则会干扰键盘锁。在多用户系统中,仅在拥有用户的窗口中显示。已弃用非系统应用。请改用TYPE_APPLICATION_OVERLAY。 | 
| TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7 | 窗口类型: 优先手机UI,即使键盘锁处于活动状态也需要显示。这些窗口不得采用输入焦点,否则会干扰键盘锁。在多用户系统中,显示在所有用户的窗口中。已弃用非系统应用。请改用TYPE_APPLICATION_OVERLAY。 | 
| TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8 | 窗口类型: 从状态栏中滑出的面板。在多用户系统中显示在所有用户的窗口中。 | 
| TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9 | 窗口类型: 键盘锁。在多用户系统中显示的对话框显示在所有用户的窗口中。 | 
| TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10 | 窗口类型: 内部系统错误窗口,出现在所有可能之上。在多用户系统中,仅在拥有用户的窗口中显示。已弃用非系统应用。请改用TYPE_APPLICATION_OVERLAY。 | 
| TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11 | 窗口类型: 内部输入法窗口,显示在普通 UI 上方。可以调整应用程序窗口的大小或平移,以便在显示此窗口时保持输入焦点可见。在多用户系统中,仅在拥有用户的窗口中显示。 | 
| TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12 | 窗口类型: 内部输入法对话框窗口,显示在当前输入法窗口上方。在多用户系统中,仅在拥有用户的窗口中显示。 | 
| TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13 | 窗口类型: 墙纸窗口,放置在任何想要坐在墙纸顶部的窗户后面。在多用户系统中,仅在拥有用户的窗口中显示。 | 
| TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14 | 窗口类型: 从状态栏上方滑出的面板。在多用户系统中显示在所有用户的窗口中。 | 
| TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15 | 窗口类型: 安全的系统覆盖窗口,需要显示在其他所有窗口之上。这些窗口不得采用输入焦点,否则会干扰键盘锁。这与TYPE_SYSTEM_OVERLAY完全相同,只是只允许系统本身创建这些叠加层。应用程序无法获取创建安全系统覆盖的权限。在多用户系统中,仅在拥有用户的窗口中显示。 | 
| TYPE_DRAG = FIRST_SYSTEM_WINDOW+16 | 窗口类型: 拖放伪窗口。只有一个拖动层(最多),它放置在所有其他窗口的顶部。在多用户系统中,仅在拥有用户的窗口中显示。 | 
| TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17 | 窗口类型: 从状态栏上方滑出的面板。 在多用户系统中显示在所有用户的窗口中。这些窗口显示在stauts 栏和任何TYPE_STATUS_BAR_PANEL窗口的顶部。 | 
| TYPE_POINTER = FIRST_SYSTEM_WINDOW+18 | 窗口类型: (鼠标)指针。 在多用户系统中显示在所有用户的窗口中。 | 
| TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19 | 窗口类型: 导航栏(与状态栏不同时)。在多用户系统中显示在所有用户的窗口中。 | 
| TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20 | 窗口类型: 用户更改系统音量时显示的音量级别叠加/对话框。在多用户系统中,显示在所有用户的窗口中。 | 
| TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21 | 窗口类型: 启动进度对话框,位于世界上所有内容的顶部。在多用户系统中,显示在所有用户的窗口中。 | 
| TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22 | 隐藏系统UI栏时使用输入事件的窗口类型。在多用户系统中,显示在所有用户的窗口中。 | 
| TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24 | 窗口类型: 导航栏面板(当导航栏与状态栏不同时)。在多用户系统中显示在所有用户的窗口中。 | 
| TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26 | 窗口类型: 显示叠加窗口。用于模拟辅助显示设备。在多用户系统中,显示在所有用户的窗口中。 | 
| TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27 | 窗口类型: 放大叠加窗口。用于在启用辅助功能放大时突出显示显示器的放大部分。在多用户系统中,显示在所有用户的窗口中。 | 
| TYPE_PRIVATE_PRESENTATION = FIRST_SYSTEM_WINDOW+30 | 窗口类型: 用于在私人虚拟显示之上进行演示的窗口。 | 
| TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31 | 窗口类型: 语音交互层中的窗口。 | 
| TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32 | 窗口类型: 仅由连接的 android.accessibilityservice.accessibilityService 覆盖的窗口,用于拦截用户交互,而无需更改辅助功能服务可以自省的窗口。特别是,辅助功能服务只能自省视力正常的用户可以与之交互的窗口,他们可以触摸这些窗口或可以在这些窗口中键入内容。例如,如果存在可触摸的全屏辅助功能叠加层,则辅助功能服务将可自检其下方的窗口,即使它们被可触摸窗口覆盖。 | 
| TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33 | 窗口类型: 语音交互层的启动窗口。 | 
| TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34 | 显示用于调整停靠堆栈大小的控点的窗口。此窗口归系统进程所有。 | 
| TYPE_QS_DIALOG = FIRST_SYSTEM_WINDOW+35 | 窗口类型: 与TYPE_APPLICATION_ATTACHED_DIALOG类似,但由快速设置磁贴使用。 | 
| TYPE_SCREENSHOT = FIRST_SYSTEM_WINDOW + 36 | 窗口类型: 直接显示在键盘上方。该图层保留用于屏幕截图动画、区域选择和 UI。在多用户系统中,仅在拥有用户的窗口中显示。 | 
| TYPE_PRESENTATION = FIRST_SYSTEM_WINDOW + 37 | 窗口类型: 用于在外部显示器上进行演示的窗口。 | 
| TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38 | 窗口类型: 应用程序覆盖窗口显示在所有活动窗口(介于FIRST_APPLICATION_WINDOW和LAST_APPLICATION_WINDOW之间的类型)上方,但显示在状态栏或 IME 等关键系统窗口下方。 系统可以随时更改这些窗口的位置、大小或可见性,以减少用户的视觉混乱并管理资源。 需要Manifest.permission.SYSTEM_ALERT_WINDOW许可。 系统将调整具有此窗口类型的进程的重要性,以减少低内存杀手杀死它们的机会。 在多用户系统中,仅在拥有用户的屏幕上显示。 | 
| TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39 | 窗口类型: 用于在其他窗口上方添加辅助功能窗口放大倍数的窗口。这会将窗口放置在叠加窗口中。 | 
| TYPE_NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40 | 窗口类型: 通知栏和键盘锁。只能有一个状态栏窗口;它放置在屏幕顶部,所有其他窗口都向下移动,因此它们位于屏幕下方。在多用户系统中,显示在所有用户的窗口中。 | 
| TYPE_STATUS_BAR_ADDITIONAL = FIRST_SYSTEM_WINDOW + 41 | 窗口类型: 用于在屏幕的非常规部分(即屏幕的左侧或底部)显示状态栏。在多用户系统中,显示在所有用户的窗口中。 | 
| LAST_SYSTEM_WINDOW = 2999 | 系统窗口类型的最大值。 | 
| INVALID_WINDOW_TYPE = -1 | 当没有合适的类型可用时,在内部使用。 | 
如状态栏窗口添加类型:
StatusBarWindowController.java:WindowManager.LayoutParams.TYPE_STATUS_BARmLp = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, mBarHeight, WindowManager.LayoutParams.TYPE_STATUS_BAR, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, PixelFormat.TRANSLUCENT); mLp.privateFlags |= PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC; mLp.token = new Binder(); mLp.gravity = Gravity.TOP; mLp.setFitInsetsTypes(0 /* types */); mLp.setTitle("StatusBar"); mLp.packageName = mContext.getPackageName(); mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; mWindowManager.addView(mStatusBarView, mLp);
2、层级值与窗口类型
2.1 WindowState
frameworks/base/services/core/java/com/android/server/wm/WindowState.java
WMS侧添加界面 添加窗口(WindowManagerImpl.java#addView -> WindowManagerGlobal.java#addView -> ViewRootImpl.java#setView -> Session extends IWindowSession.Stub#addToDisplayAsUser -> WindowManagerService.java#addWindow)时初始化一个窗口的WindowState,窗口管理器中的一个窗口。记录一个窗口应该有的全部属性
final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], attrs, viewVisibility, session.mUid, userId,
                    session.mCanAddInternalSystemWindow);
win.attach();
mWindowMap.put(client.asBinder(), win);
mToken = token是WindowToken句柄,用于显示窗口的活动的句柄。
mSession = s此类表示活动的客户端会话。通常每个进程都有一个与窗口管理器交互的会话对象。
mAttrs.copyFrom(a)窗口属性WindowManager.LayoutParams
mBaseLayer根据窗口类型在屏幕上的排序方式。mBaseLayer = mPolicy.getWindowLayerLw(parentWindow) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET:TYPE_LAYER_MULTIPLIER将策略的类型层乘以多少,以便为相同类型的多个窗口保留空间,并使用TYPE_LAYER_OFFSET进行 Z 排序调整。TYPE_LAYER_OFFSET偏移TYPE_LAYER_MULTIPLIER,用于将一组窗口移动到同一图层中其他窗口的上方或下方。
mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type)根据子窗口附加到的窗口对子窗口进行 Z 排序。返回正数以将它们排在前面,负数在后面排序。
mIsChildWindow:是否是子窗口;mIsImWindow:是否是输入法窗口;mIsWallpaper:是否是壁纸窗口。
mWinAnimator = new WindowStateAnimator(this)跟踪单个 WindowState 的动画和图面操作。
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
        WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
        int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow,
        PowerManagerWrapper powerManagerWrapper) {
    super(service);
    mTmpTransaction = service.mTransactionFactory.get();
    mSession = s;
    mClient = c;
    mAppOp = appOp;
    mToken = token;
    mActivityRecord = mToken.asActivityRecord();
    mOwnerUid = ownerId;
    mShowUserId = showUserId;
    mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;
    mWindowId = new WindowId(this);
    mAttrs.copyFrom(a);
    mLastSurfaceInsets.set(mAttrs.surfaceInsets);
    mViewVisibility = viewVisibility;
    mPolicy = mWmService.mPolicy;
    mContext = mWmService.mContext;
    DeathRecipient deathRecipient = new DeathRecipient();
    mPowerManagerWrapper = powerManagerWrapper;
    mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
    mInputWindowHandle = new InputWindowHandleWrapper(new InputWindowHandle(
            mActivityRecord != null
                    ? mActivityRecord.getInputApplicationHandle(false /* update */) : null,
            getDisplayId()));
    mInputWindowHandle.setOwnerPid(s.mPid);
    mInputWindowHandle.setOwnerUid(s.mUid);
    mInputWindowHandle.setName(getName());
    mInputWindowHandle.setPackageName(mAttrs.packageName);
    mInputWindowHandle.setLayoutParamsType(mAttrs.type);
    // Check private trusted overlay flag and window type to set trustedOverlay variable of
    // input window handle.
    mInputWindowHandle.setTrustedOverlay(
            ((mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0
                    && mOwnerCanAddInternalSystemWindow)
                    || InputMonitor.isTrustedOverlay(mAttrs.type));
    if (DEBUG) {
        Slog.v(TAG, "Window " + this + " client=" + c.asBinder()
                        + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
    }
    try {
        c.asBinder().linkToDeath(deathRecipient, 0);
    } catch (RemoteException e) {
        mDeathRecipient = null;
        mIsChildWindow = false;
        mLayoutAttached = false;
        mIsImWindow = false;
        mIsWallpaper = false;
        mIsFloatingLayer = false;
        mBaseLayer = 0;
        mSubLayer = 0;
        mWinAnimator = null;
        mWpcForDisplayAreaConfigChanges = null;
        return;
    }
    mDeathRecipient = deathRecipient;
    if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
        // The multiplier here is to reserve space for multiple
        // windows in the same type layer.
        mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
                * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
        mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
        mIsChildWindow = true;
        mLayoutAttached = mAttrs.type !=
                WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
        mIsImWindow = parentWindow.mAttrs.type == TYPE_INPUT_METHOD
                || parentWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
        mIsWallpaper = parentWindow.mAttrs.type == TYPE_WALLPAPER;
    } else {
        // The multiplier here is to reserve space for multiple
        // windows in the same type layer.
        mBaseLayer = mPolicy.getWindowLayerLw(this)
                * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
        mSubLayer = 0;
        mIsChildWindow = false;
        mLayoutAttached = false;
        mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
                || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
        mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
    }
    mIsFloatingLayer = mIsImWindow || mIsWallpaper;
    if (mActivityRecord != null && mActivityRecord.mShowForAllUsers) {
        // Windows for apps that can show for all users should also show when the device is
        // locked.
        mAttrs.flags |= FLAG_SHOW_WHEN_LOCKED;
    }
    mWinAnimator = new WindowStateAnimator(this);
    mWinAnimator.mAlpha = a.alpha;
    mRequestedWidth = 0;
    mRequestedHeight = 0;
    mLastRequestedWidth = 0;
    mLastRequestedHeight = 0;
    mLayer = 0;
    mOverrideScale = mWmService.mAtmService.mCompatModePackages.getCompatScale(
            mAttrs.packageName, s.mUid);
    // Make sure we initial all fields before adding to parentWindow, to prevent exception
    // during onDisplayChanged.
    if (mIsChildWindow) {
        ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", this, parentWindow);
        parentWindow.addChild(this, sWindowSubLayerComparator);
    }
    // System process or invalid process cannot register to display area config change.
    mWpcForDisplayAreaConfigChanges = (s.mPid == MY_PID || s.mPid < 0)
            ? null
            : service.mAtmService.getProcessController(s.mPid, s.mUid);
}
2.2 WindowManagerPolicy 窗口管理的策略机制
窗 口 管 理 的 策 略 机 制
frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
getWindowLayerFromTypeLw方法,窗口类型的图层分配。允许您控制不同类型的窗口在屏幕上的排序方式。上面mBaseLayer以该返回值为基础计算。
- 窗口类型Type在
FIRST_APPLICATION_WINDOW~LAST_APPLICATION_WINDOW之间(即Application Window普通应用程序窗口1~99),返回APPLICATION_LAYER = 2
getMaxWindowLayer()最大窗口图层。请注意,最大窗口层应高于getWindowLayerFromTypeLw报告的最大值。(最大图层值是36,这里1~35被使用,其中APPLICATION_LAYER = 2为Application Window普通应用程序窗口使用)
| 窗口类型 Type | 返回的基础层级值 | 
|---|---|
| FIRST_APPLICATION_WINDOW ~ LAST_APPLICATION_WINDOW | APPLICATION_LAYER = 2 | 
| TYPE_WALLPAPER | 1 | 
| TYPE_PRESENTATION TYPE_PRIVATE_PRESENTATION TYPE_DOCK_DIVIDER TYPE_QS_DIALOG TYPE_PHONE | 3 | 
| TYPE_SEARCH_BAR TYPE_VOICE_INTERACTION_STARTING | 4 | 
| TYPE_VOICE_INTERACTION | 5 | 
| TYPE_INPUT_CONSUMER | 6 | 
| TYPE_SYSTEM_DIALOG | 7 | 
| TYPE_TOAST | 8 | 
| TYPE_PRIORITY_PHONE | 9 | 
| TYPE_SYSTEM_ALERT | canAddInternalSystemWindow ? 13 : 10 | 
| TYPE_APPLICATION_OVERLAY | 12 | 
| TYPE_INPUT_METHOD | 15 | 
| TYPE_INPUT_METHOD_DIALOG | 16 | 
| TYPE_STATUS_BAR | 17 | 
| TYPE_STATUS_BAR_ADDITIONAL | 18 | 
| TYPE_NOTIFICATION_SHADE | 19 | 
| TYPE_STATUS_BAR_SUB_PANEL | 20 | 
| TYPE_KEYGUARD_DIALOG | 21 | 
| TYPE_VOLUME_OVERLAY | 22 | 
| TYPE_SYSTEM_OVERLAY | canAddInternalSystemWindow ? 23 : 11 | 
| TYPE_NAVIGATION_BAR | 24 | 
| TYPE_NAVIGATION_BAR_PANEL | 25 | 
| TYPE_SCREENSHOT | 26 | 
| TYPE_SYSTEM_ERROR | canAddInternalSystemWindow ? 27 : 10 | 
| TYPE_MAGNIFICATION_OVERLAY | 28 | 
| TYPE_DISPLAY_OVERLAY | 29 | 
| TYPE_DRAG | 30 | 
| TYPE_ACCESSIBILITY_OVERLAY | 31 | 
| TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY | 32 | 
| TYPE_SECURE_SYSTEM_OVERLAY | 33 | 
| TYPE_BOOT_PROGRESS | 34 | 
| TYPE_POINTER | 35 | 
| 默认情况default | 3 | 
default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow,
         boolean roundedCornerOverlay) {
     // Always put the rounded corner layer to the top most.
     if (roundedCornerOverlay && canAddInternalSystemWindow) {
         return getMaxWindowLayer();
     }
     if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
         return APPLICATION_LAYER;
     }
     switch (type) {
         case TYPE_WALLPAPER:
             // wallpaper is at the bottom, though the window manager may move it.
             return  1;
         case TYPE_PRESENTATION:
         case TYPE_PRIVATE_PRESENTATION:
         case TYPE_DOCK_DIVIDER:
         case TYPE_QS_DIALOG:
         case TYPE_PHONE:
             return  3;
         case TYPE_SEARCH_BAR:
         case TYPE_VOICE_INTERACTION_STARTING:
             return  4;
         case TYPE_VOICE_INTERACTION:
             // voice interaction layer is almost immediately above apps.
             return  5;
         case TYPE_INPUT_CONSUMER:
             return  6;
         case TYPE_SYSTEM_DIALOG:
             return  7;
         case TYPE_TOAST:
             // toasts and the plugged-in battery thing
             return  8;
         case TYPE_PRIORITY_PHONE:
             // SIM errors and unlock.  Not sure if this really should be in a high layer.
             return  9;
         case TYPE_SYSTEM_ALERT:
             // like the ANR / app crashed dialogs
             // Type is deprecated for non-system apps. For system apps, this type should be
             // in a higher layer than TYPE_APPLICATION_OVERLAY.
             return  canAddInternalSystemWindow ? 13 : 10;
         case TYPE_APPLICATION_OVERLAY:
             return  12;
         case TYPE_INPUT_METHOD:
             // on-screen keyboards and other such input method user interfaces go here.
             return  15;
         case TYPE_INPUT_METHOD_DIALOG:
             // on-screen keyboards and other such input method user interfaces go here.
             return  16;
         case TYPE_STATUS_BAR:
             return  17;
         case TYPE_STATUS_BAR_ADDITIONAL:
             return  18;
         case TYPE_NOTIFICATION_SHADE:
             return  19;
         case TYPE_STATUS_BAR_SUB_PANEL:
             return  20;
         case TYPE_KEYGUARD_DIALOG:
             return  21;
         case TYPE_VOLUME_OVERLAY:
             // the on-screen volume indicator and controller shown when the user
             // changes the device volume
             return  22;
         case TYPE_SYSTEM_OVERLAY:
             // the on-screen volume indicator and controller shown when the user
             // changes the device volume
             return  canAddInternalSystemWindow ? 23 : 11;
         case TYPE_NAVIGATION_BAR:
             // the navigation bar, if available, shows atop most things
             return  24;
         case TYPE_NAVIGATION_BAR_PANEL:
             // some panels (e.g. search) need to show on top of the navigation bar
             return  25;
         case TYPE_SCREENSHOT:
             // screenshot selection layer shouldn't go above system error, but it should cover
             // navigation bars at the very least.
             return  26;
         case TYPE_SYSTEM_ERROR:
             // system-level error dialogs
             return  canAddInternalSystemWindow ? 27 : 10;
         case TYPE_MAGNIFICATION_OVERLAY:
             // used to highlight the magnified portion of a display
             return  28;
         case TYPE_DISPLAY_OVERLAY:
             // used to simulate secondary display devices
             return  29;
         case TYPE_DRAG:
             // the drag layer: input for drag-and-drop is associated with this window,
             // which sits above all other focusable windows
             return  30;
         case TYPE_ACCESSIBILITY_OVERLAY:
             // overlay put by accessibility services to intercept user interaction
             return  31;
         case TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY:
             return 32;
         case TYPE_SECURE_SYSTEM_OVERLAY:
             return  33;
         case TYPE_BOOT_PROGRESS:
             return  34;
         case TYPE_POINTER:
             // the (mouse) pointer layer
             return  35;
         default:
             Slog.e("WindowManager", "Unknown window type: " + type);
             return 3;
     }
 }
2.3 WindowToken句柄
frameworks/base/services/core/java/com/android/server/wm/WindowToken.java
窗口管理器中一组相关窗口的容器。通常,这是一个AppWindowToken,它是用于显示窗口的活动的句柄。对于嵌套窗口,为父窗口创建了一个 WindowToken 来管理其子窗口。
WindowToken build() {
    return new WindowToken(mService, mToken, mType, mPersistOnEmpty, mDisplayContent,
            mOwnerCanManageAppTokens, mRoundedCornerOverlay, mFromClientToken, mOptions);
}

3、窗口属性 LayoutParams
android/view/WindowManager.java # WindowManager.LayoutParams
-  type如目录1,不在赘述
-  flags窗口的标志flags 描述 FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001窗口标志:只要此窗口对用户可见,就允许在屏幕打开时激活锁定屏幕。这可以单独使用,也可以与 FLAG_KEEP_SCREEN_ON和FLAG_SHOW_WHEN_LOCKED结合使用FLAG_DIM_BEHIND = 0x00000002窗口标志:此窗口后面的所有内容都将变暗。使用 dimAmount 控制 dim 的量。 FLAG_BLUR_BEHIND = 0x00000004窗口标志:为此窗口启用后面的模糊。 FLAG_NOT_FOCUSABLE = 0x00000008窗口标志:此窗口永远不会获取键输入焦点,因此用户无法向其发送键或其他按钮事件。相反,这些将转到它后面的任何可聚焦窗口。此标志还将启用 FLAG_NOT_TOUCH_MODAL是否显式设置。设置此标志还意味着窗口不需要与软输入法交互,因此它将独立于任何活动输入法进行 Z 排序和定位(通常这意味着它在输入法的顶部获得 Z 排序,因此它可以对其内容使用全屏并在需要时覆盖输入法。可以使用FLAG_ALT_FOCUSABLE_IM来修改此行为。FLAG_NOT_TOUCHABLE = 0x00000010窗口标志:此窗口永远无法接收触摸事件。此标志的目的是让触摸由此窗口下方的某个窗口处理(按 Z 顺序)。 FLAG_NOT_TOUCH_MODAL = 0x00000020窗口标志:即使此窗口可聚焦(未设置其 FLAG_NOT_FOCUSABLE),也允许将窗口外的任何指针事件发送到其后面的窗口。否则,它将使用所有指针事件本身,无论它们是否在窗口内。FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040窗口标志:设置后,如果按下触摸屏时设备处于睡眠状态,您将收到此第一个触摸事件。通常,系统使用第一个触摸事件,因为用户看不到他们正在按下的内容。 已弃用 此标志不起作用。FLAG_KEEP_SCREEN_ON = 0x00000080窗口标志:只要此窗口对用户可见,请保持设备的屏幕打开并明亮。 FLAG_LAYOUT_IN_SCREEN = 0x00000100附加窗口的窗口标志:将窗口放在整个屏幕内,忽略父窗口的任何约束。 FLAG_LAYOUT_NO_LIMITS = 0x00000200窗口标志:允许窗口延伸到屏幕之外。 FLAG_FULLSCREEN = 0x00000400窗口标志:显示此窗口时隐藏所有屏幕装饰(如状态栏)。这允许窗口将整个显示空间用于自身 - 当设置了此标志的应用窗口位于顶层时,状态栏将被隐藏。全屏窗口将忽略窗口的软输入模式字段的值 SOFT_INPUT_ADJUST_RESIZE;窗口将保持全屏显示,并且不会调整大小。
 可以通过安卓在您的主题中控制此标志。R.attr.windowFullscreen属性;此属性在标准全屏主题中自动为您设置,例如android.R.style.Theme_NoTitleBar_Fullscreen, android.R.style.Theme_Black_NoTitleBar_Fullscreen, android.R.style.Theme_Light_NoTitleBar_Fullscreen, android.R.style.Theme_Holo_NoActionBar_Fullscreen, android.R.style.Theme_Holo_Light_NoActionBar_Fullscreen, android.R.style.Theme_DeviceDefault_NoActionBar_Fullscreen, and android.R.style.Theme_DeviceDefault_Light_NoActionBar_Fullscreen。已弃用 WindowInsetsController.hide(int) 和 WindowInsets.Type.statusBars() 代替。FLAG_FORCE_NOT_FULLSCREEN = 0x00000800窗口标志:覆盖FLAG_FULLSCREEN并强制显示屏幕装饰(如状态栏)。 已弃用 此值“意外”成为 API,不应由第三方应用程序使用。FLAG_DITHER = 0x00001000窗口标志:将此窗口合成到屏幕时打开抖动。 已弃用 不再使用此标志。FLAG_SECURE = 0x00002000窗口标志:将窗口内容视为安全内容,防止其显示在屏幕截图中或在不安全的显示器上查看。有关安全表面和安全显示器的更多详细信息,请参阅 Display.FLAG_SECURE。FLAG_SCALED = 0x00004000窗口标志:一种特殊模式,其中布局参数用于在将表面合成到屏幕时对表面执行缩放。 FLAG_IGNORE_CHEEK_PRESSES = 0x00008000窗口标志:用于当用户将屏幕靠在脸上时经常使用的窗口,它将主动过滤事件流以防止在这种情况下意外按下特定窗口可能不需要,当检测到此类事件流时,应用程序将收到 CANCEL 运动事件以指示这一点,以便应用程序可以通过不对事件执行任何操作来相应地处理此问题,直到松开手指。 FLAG_LAYOUT_INSET_DECOR = 0x00010000窗口标志:仅与FLAG_LAYOUT_IN_SCREEN结合使用的特殊选项。在屏幕中请求布局时,您的窗口可能会显示在屏幕装饰(如状态栏)的顶部或后面。通过包含此标志,窗口管理器将报告确保您的内容未被屏幕装饰覆盖所需的内嵌矩形。此标志通常由 Window 为您设置,如 Window.setFlags 中所述。 已弃用。FLAG_ALT_FOCUSABLE_IM = 0x00020000窗口标志:设置后,反转窗口的输入法可聚焦性。设置此标志的效果取决于是否设置了 FLAG_NOT_FOCUSABLE:
 如果未设置FLAG_NOT_FOCUSABLE,即当窗口可聚焦时,设置此标志可防止此窗口成为输入法的目标。因此,它将无法与输入法交互,并且将分层在输入法之上(除非它上面有另一个输入法目标)。
 如果设置了FLAG_NOT_FOCUSABLE,则设置此标志会将窗口请求为输入法目标,即使窗口不可聚焦也是如此。因此,它将在输入法下方分层。注意: 设置FLAG_NOT_FOCUSABLE的窗口无法与输入法交互,无论此标志如何。FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000窗口标志:如果已设置 FLAG_NOT_TOUCH_MODAL,则可以将此标志设置为接收单个特殊的MotionEvent,其中包含针对窗外发生的触摸的操作MotionEvent.ACTION_OUTSIDE。请注意,您不会收到完整的向下/移动/向上手势,只会收到第一次向下的位置作为ACTION_OUTSIDE。FLAG_SHOW_WHEN_LOCKED = 0x00080000窗口标志:在屏幕锁定时允许显示窗口的特殊标志。这将使应用程序窗口优先于密钥保护或任何其他锁定屏幕。可与FLAG_KEEP_SCREEN_ON一起使用,在显示钥匙保护窗口之前直接打开屏幕和显示窗口。可与FLAG_DISMISS_KEYGUARD一起使用,以自动完全关闭不安全的键盘锁。此标志仅适用于最顶层的全屏窗口。 已弃用 使用。android.R.attr.showWhenLocked或android.app.Activity.setShowWhenLocked(boolean),以防止无意的双重生命周期事件FLAG_SHOW_WALLPAPER = 0x00100000窗口标志:要求在窗口后面显示系统墙纸。窗口表面必须是半透明的,才能实际看到它后面的墙纸;此标志只是确保如果此窗口实际上具有半透明区域,则墙纸表面将在那里。 
 可以通过安卓在您的主题中控制此标志。R.attr.windowShowWallpaper属性;此属性在标准壁纸主题中自动为您设置,例如android.R.style.Theme_Wallpaper, android.R.style.Theme_Wallpaper_NoTitleBar, android.R.style.Theme_Wallpaper_NoTitleBar_Fullscreen, android.R.style.Theme_Holo_Wallpaper, android.R.style.Theme_Holo_Wallpaper_NoTitleBar, android.R.style.Theme_DeviceDefault_Wallpaper, and android.R.style.Theme_DeviceDefault_Wallpaper_NoTitleBar.FLAG_TURN_SCREEN_ON = 0x00200000窗口标志:当设置为正在添加或使其可见的窗口时,一旦窗口显示,系统将戳电源管理器的用户活动(就好像用户唤醒了设备)以打开屏幕。 已弃用 使用。android.R.attr.turnScreenOn或android.app.Activity.setTurnScreenOn(boolean),以防止意外的双重生命周期事件FLAG_DISMISS_KEYGUARD = 0x00400000窗口标志:设置窗口时,仅当它不是安全锁键盘锁时,窗口才会导致键盘锁被关闭。由于安全不需要此类键盘锁,因此如果用户导航到另一个窗口,它将永远不会重新出现(与 FLAG_SHOW_WHEN_LOCKED相反,只会暂时隐藏安全和非安全键盘锁,但确保当用户移动到另一个不隐藏它们的 UI 时它们会重新出现)。如果键盘锁当前处于活动状态且安全(需要解锁凭据),则用户仍需要在看到此窗口之前进行确认,除非还设置了FLAG_SHOW_WHEN_LOCKED。已弃用。FLAG_SHOW_WHEN_LOCKED或KeyguardManager.requestDismissKeyguard。由于只要窗口上有此标志的活动聚焦,键盘锁就会一直被关闭,因此键盘卫士无法防止无意中触摸屏幕,这是不希望的FLAG_SPLIT_TOUCH = 0x00800000窗口标志:设置后,窗口将接受将超出其边界的触摸事件发送到也支持拆分触摸的其他窗口。如果未设置此标志,则第一个向下的指针确定所有后续触摸都指向的窗口,直到所有指针上升为止。设置此标志后,每个指针(不一定是第一个指针)将确定该指针的所有后续触摸将转到的窗口,直到该指针上升,从而使具有多个指针的触摸能够拆分到多个窗口。 FLAG_HARDWARE_ACCELERATED = 0x01000000指示是否应对此窗口进行硬件加速。请求硬件加速并不能保证它会发生。 
 只能以编程方式控制此标志以启用硬件加速。若要以编程方式为给定窗口启用硬件加速,请执行以下操作:Window w = activity.getWindow(); // in Activity's onCreate()例如w.setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
 请务必记住,在设置活动或对话框的内容视图之前,必须设置此标志。
 此标志不能用于禁用硬件加速,因为它在您的清单中使用android.R.attr.hardwareAccelerated。如果需要有选择地以编程方式禁用硬件加速(例如,用于自动测试),请确保在清单中将其关闭,并在需要时使用上述方法在活动或对话框中启用它。
 如果在活动或应用程序上将android:hardwareAcceleratedXML 属性设置为 true,则系统会自动设置此标志。FLAG_LAYOUT_IN_OVERSCAN = 0x02000000窗口标志:允许窗口内容延伸到屏幕的过扫描区域(如果有)。窗口仍应正确定位其内容,以考虑过扫描区域。 
 可以通过android.R.attr.windowOverscan属性;此属性在标准过扫描主题中自动为您设置,例如android.R.style.Theme_Holo_NoActionBar_Overscan, android.R.style.Theme_Holo_Light_NoActionBar_Overscan, android.R.style.Theme_DeviceDefault_NoActionBar_Overscan, and android.R.style.Theme_DeviceDefault_Light_NoActionBar_Overscan.
 为窗口启用此标志时,其正常内容可能会被显示器的过扫描区域在某种程度上遮挡。若要确保该内容的关键部分对用户可见,可以使用View.setFitsSystemWindows(boolean)在视图层次结构中设置应应用适当偏移量的点。(这可以通过直接调用此函数来完成,使用android.R.attr.fitsSystemWindows属性在您的视图层次结构中,或实现您自己的View.fitSystemWindows(Rect)方法)。
 这种定位内容元素的机制与布局和View.setSystemUiVisibility(int)的等效用法相同;下面是一个示例布局,它将正确定位其 UI 元素,并设置了此过扫描标志:已弃用 从Android 11开始,任何Android产品都不再设置过扫描区域。FLAG_TRANSLUCENT_STATUS = 0x04000000窗口标志:请求具有最少系统提供的背景保护的半透明状态栏。 
 可以通过android.R.attr.windowTranslucentStatus属性;此属性会在标准半透明装饰主题中自动为您设置,例如android.R.style.Theme_Holo_NoActionBar_TranslucentDecor, android.R.style.Theme_Holo_Light_NoActionBar_TranslucentDecor, android.R.style.Theme_DeviceDefault_NoActionBar_TranslucentDecor, and android.R.style.Theme_DeviceDefault_Light_NoActionBar_TranslucentDecor.
 为窗口启用此标志后,它会自动将系统 UI 可见性标志设置为View.SYSTEM_UI_FLAG_LAYOUT_STABLE和View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN。已弃用 改用半透明颜色的。Window.setStatusBarColor(int)FLAG_TRANSLUCENT_NAVIGATION = 0x08000000窗口标志:请求具有最少系统提供的背景保护的半透明导航栏。 
 已弃用 改用半透明颜色的Window.setNavigationBarColor(int)。FLAG_LOCAL_FOCUS_MODE = 0x10000000标记本地焦点模式下的窗口。本地焦点模式下的窗口可以使用 Window.setLocalFocus(boolean, boolean)独立于窗口管理器控制焦点。通常,此模式下的窗口不会从窗口管理器获取触摸/键事件,但只能通过使用Window.injectInputEvent(InputEvent)通过本地注入获取事件。FLAG_SLIPPERY = 0x20000000窗口标志:使触摸能够在手势中间从窗口滑出到相邻窗口,而不是在手势持续时间内被捕获。此标志仅更改此窗口的触摸焦点的行为。触摸可以滑出窗口,但不一定能滑回窗口(除非具有触摸焦点的另一个窗口允许)。 FLAG_LAYOUT_ATTACHED_IN_DECOR = 0x40000000窗口标志:请求使用附加窗口进行布局时,附加的窗口可能与父窗口(如导航栏)的屏幕修饰重叠。通过包含此标志,窗口管理器将在父窗口的装饰框架内布局附加的窗口,使其不与屏幕装饰重叠。 已弃用 使用。setFitInsetsTypes(int)来确定附加的窗口是否与系统栏重叠FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000指示此窗口负责绘制系统条形的背景的标志。如果设置,系统栏将以透明背景绘制,并且此窗口中的相应区域将用 Window.getStatusBarColor()和Window.getNavigationBarColor()中指定的颜色填充。
-  softInputMode: 任何软输入区域所需的操作模式。可以是以下各项的任意组合:其中一个可见性状态SOFT_INPUT_STATE_UNSPECIFIED、SOFT_INPUT_STATE_UNCHANGED、SOFT_INPUT_STATE_HIDDEN、SOFT_INPUT_STATE_ALWAYS_HIDDEN、SOFT_INPUT_STATE_VISIBLE或SOFT_INPUT_STATE_ALWAYS_VISIBLE。其中一个调整选项SOFT_INPUT_ADJUST_UNSPECIFIED、SOFT_INPUT_ADJUST_RESIZE、SOFT_INPUT_ADJUST_PAN或SOFT_INPUT_ADJUST_NOTHING。可以通过android.R.attr.windowSoftInputMode属性。
-  alpha = 1.0f要应用于整个窗口的 alpha 值。alpha 为 1.0 表示完全不透明,0.0 表示完全透明
-  systemUiVisibility控制状态栏的可见性。已弃用:SystemUiVisibility标志已弃用。请改用WindowInsetsController。另请参阅:View.STATUS_BAR_VISIBLE,View.STATUS_BAR_HIDDEN





















