首页
300FIT NETWORK中文网
领取MOLI红包

300FIT NETWORK中文网

你的位置:FITFI中文网 > 300FIT NETWORK中文网 > 你知道 Android 是如何管理复杂的 Window 层级的?

你知道 Android 是如何管理复杂的 Window 层级的?

发布日期:2025-01-04 17:50    点击次数:112

App 开发者的不知有没有发现,StatusBar 一直是盖在 App 上面,不管是修改颜色,或者是写悬浮框,都无法盖住 StatusBar。framework 开发,会出现一些定制,如盖住 StatusBar,不了解的可能用错,出现一些不必要的 bug,官方文档也没有列出 Window 层级的规则。所以希望通过下文给大家分享,Android 是如何制定显示层级规则的。大概说下 Window 在 Android 中的概念其实也可以好理解,和经常使用 Windows 操作系统一样,打开一个应用,出现界面,我们可以理解出现了一个窗口,所以 Window ≠ View。一个 Activity 可以理解 对应一个 Window,理解源码的同学知道:ViewRootImpl 是对应一个 Window。怎么看 Window 呢?adb shell dumpsys window 抽取了几个典型的Window如下: Window #2 Window{911875c u0 NavigationBar0}://导航栏   ty=NAVIGATION_BAR   isOnScreen=true   isVisible=true Window #4 Window{bf1a956 u0 StatusBar}://状态栏   ty=STATUS_BAR   isOnScreen=true   isVisible=true Window #11 Window{d377ae1 u0 InputMethod}://输入法,不显示   ty=INPUT_METHOD   isOnScreen=false   isVisible=false Window #12 Window{e190206 u0 com.android.settings/com.android.settings.Settings}://打开 App activity   ty=BASE_LICATION   isOnScreen=true   isVisible=true Window #16 Window{abcabb9 u0 com.android.systemui.ImageWallpaper}://壁纸   ty=WALLPAPER   isOnScreen=false   isVisible=false一般手机都会存在以上 Window,层级顺序从高 -> 低。显示 PopWindow Window #11 Window{513f711 u0 PopupWindow:3e4bfb}:    ty=LICATION_SUB_PANEL    isOnScreen=true    sVisible=true显示 DialogWindow #11 Window{a08f90b }:   ty=LICATION   isOnScreen=true   isVisible=true不难看出,Window 层级与 ty 有关系的,ty 是 type 的简写。Window 的分类Application Window:应用程序窗口type 取值范围 [1,99]/**  * Start of window types that represent normal lication windows.  */ public static final int FIRST_LICATION_WINDOW = 1; // activity 会使用 此 type public static final int TYPE_BASE_LICATION   = 1; // dialog 会使用 此 type public static final int TYPE_LICATION        = 2; // 冷启动会显示的 Window,真正启动页面显示之前的画面 public static final int TYPE_LICATION_STARTING = 3; // 没玩过 public static final int TYPE_DRAWN_LICATION = 4; /**  * End of types of lication windows.  */ public static final int LAST_LICATION_WINDOW = 99;Sub Window:子窗口子窗口:顾名思义,对应有主窗口。子窗口需要附在主窗口上,如 PopWindowtype 取值范围 [1000,1999]/**  * Start of types of sub-windows.  The {@link #token} of these windows  * must be set to the window they are attached to.  These types of  * windows are kept next to their attached window in Z-order, and their  * coordinate space is relative to their attached window.  */ public static final int FIRST_SUB_WINDOW = 1000; public static final int TYPE_LICATION_PANEL = FIRST_SUB_WINDOW; public static final int TYPE_LICATION_MEDIA = FIRST_SUB_WINDOW + 1; public static final int TYPE_LICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2; public static final int TYPE_LICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3; public static final int TYPE_LICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW + 4; public static final int TYPE_LICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5; /**  * End of types of sub-windows.  */ public static final int LAST_SUB_WINDOW = 1999;System Window :系统窗口type 取值范围 [2000,2999]如 Toast,ANR 窗口,输入法,StatusBar,NavigationBar 等。/**  * Start of system-specific window types.  These are not normally  * created by lications.  */ public static final int FIRST_SYSTEM_WINDOW     = 2000; public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW; public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1; public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2; /**  * End of types of system windows.  */ public static final int LAST_SYSTEM_WINDOW      = 2999;之前好像看过文章说 type 值越大,层级越高, 这个观点是错的。具体层级是下面逻辑代码,返回值越大,层级越高,最终在屏幕上显示时就越靠近用户。frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java /**  * Returns the layer assignment for the window type. Allows you to control how different  * kinds of windows are ordered on-screen.  *  * @param type The type of window being assigned.  * @param canAddInternalSystemWindow If the owner window associated with the type we are  *        evaluating can add internal system windows. I.e they have  *        {@link Manifest.permission#INTERNAL_SYSTEM_WINDOW}. If true, alert window  *        types {@link android.view.WindowManager.LayoutParams#isSystemAlertWindowType(int)}  *        can be assigned layers greater than the layer for  *        {@link android.view.WindowManager.LayoutParams#TYPE_LICATION_OVERLAY} Else, their  *        layers would be lesser.  * @param roundedCornerOverlay {#code true} to indicate that the owner window is rounded corner  *                             overlay.  * @return int An arbitrary integer used to order windows, with lower numbers below higher ones.  */ 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_LICATION_WINDOW && type <= LAST_LICATION_WINDOW) {         return LICATION_LAYER;// LICATION_LAYER = 2     }     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 s.             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 /  crashed dialogs             // Type is deprecated for non-system s. For system s, this type should be             // in a higher layer than TYPE_LICATION_OVERLAY.             return  canAddInternalSystemWindow ? 13 : 10;         case TYPE_LICATION_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;     } }以上方法,返回 layer,type -> layer,以上代码可以得到如下信息。layer 取值范围 【1,36】App 对应 APPLICATION_LAYER,值为 2,仅比 TYPE_WALLPAPER 大Window 层级具体是怎么计算的呢?从 System Window 中 基本已经找到答案。本章节具体说下实现细节:mBaseLayer & mSubLayer用来计算层级的两个参数mSubLayer:用来计算子窗口的层级,默认值为 0mBaseLayer:用来计算主窗口的层级。frameworks/base/services/core/java/com/android/server/wm/WindowState.java if mAttrs.type = FIRST_SUB_WINDOW && mAttrs.type = LAST_SUB_WINDOW {     mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)             * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;// layer * 10000 + 1000     mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type); } else {     mBaseLayer = mPolicy.getWindowLayerLw(this)             * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;// layer * 10000 + 1000     mSubLayer = 0; }WindowState 中 mBaseLayer,mSubLayermBaseLayer:主窗口的 type 对应 value ,计算如下如 Activity,type 是 TYPE_BASE_APPLICATION ,getWindowLayerLw 计算返回 APPLICATION_LAYER(2),mBaseLayer = 2 * 10000 + 1000TYPE_LAYER_MULTIPLIER:为什么要 * 10000,将阈值扩大 10000 倍,系统中可能存在相同类型的窗口有很多。TYPE_LAYER_OFFSET:为了移动同一层级的一组窗口以上两个常量具体怎么使用,没有研究,该值不影响本文的分析。mSubLayer:计算规则如下,取值范围 [-2,3],TYPE_APPLICATION_ATTACHED_DIALOG 值为 1,APPLICATION_MEDIA_SUBLAYER 值为 -2,看到这里就可以想到子窗口是可以在主窗口下方,主窗口如果可以看到子窗口,必须透明。frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java default int getSubWindowLayerFromTypeLw(int type) {     switch (type) {         case TYPE_LICATION_PANEL:         case TYPE_LICATION_ATTACHED_DIALOG:             return LICATION_PANEL_SUBLAYER;// 1         case TYPE_LICATION_MEDIA:             return LICATION_MEDIA_SUBLAYER;// -2         case TYPE_LICATION_MEDIA_OVERLAY:             return LICATION_MEDIA_OVERLAY_SUBLAYER;// -1         case TYPE_LICATION_SUB_PANEL:             return LICATION_SUB_PANEL_SUBLAYER; // 2         case TYPE_LICATION_ABOVE_SUB_PANEL:             return LICATION_ABOVE_SUB_PANEL_SUBLAYER;// 3     }     Slog.e("WindowManager", "Unknown sub-window type: " + type);     return 0; }Sub Window 排序frameworks/base/services/core/java/com/android/server/wm/WindowState.java /**  * Compares two window sub-layers and returns -1 if the first is lesser than the second in terms  * of z-order and 1 otherwise.  */ private static final Comparator<WindowState> sWindowSubLayerComparator =         new Comparator<WindowState>() {             @Override             public int compare(WindowState w1, WindowState w2) {                 final int layer1 = w1.mSubLayer;                 final int layer2 = w2.mSubLayer;                 if (layer1 < layer2 

Powered by FITFI中文网 @2013-2022 RSS地图 HTML地图

Copyright Powered by站群 © 2013-2024