当前位置:   article > 正文

一文了解 Window 层级顺序_adb查看window层级

adb查看window层级

App开发者的不知有没有发现,StatusBar 一直是盖在App 上面,不管是修改颜色,或者是写悬浮框,都无法盖住StatusBar。framework 开发,会出现一些定制,如盖住 StatusBar,不了解的可能用错,出现一些不必要的bug,官方文档也没有列出 Window 层级的规则。
所以希望通过下文给大家分享,Android 是如何制定显示层级规则的。

大概说下 Window 在 Android 中的概念
其实也可以好理解,和经常使用 Windows 操作系统一样,打开一个应用,出现界面,我们可以理解出现了一个窗口,所以 Window ≠ View

一个Activity 可以理解 对应一个 Window,理解源码的同学知道: ViewRootImpl 是对应一个 Window。

怎么看 Window 呢?

  1. adb shell dumpsys window
  2. 抽取了几个典型的Window如下:
  3. Window #2 Window{911875c u0 NavigationBar0}://导航栏
  4. ty=NAVIGATION_BAR
  5. isOnScreen=true
  6. isVisible=true
  7. Window #4 Window{bf1a956 u0 StatusBar}://状态栏
  8. ty=STATUS_BAR
  9. isOnScreen=true
  10. isVisible=true
  11. Window #11 Window{d377ae1 u0 InputMethod}://输入法,不显示
  12. ty=INPUT_METHOD
  13. isOnScreen=false
  14. isVisible=false
  15. Window #12 Window{e190206 u0 com.android.settings/com.android.settings.Settings}://打开 App activity
  16. ty=BASE_APPLICATION
  17. isOnScreen=true
  18. isVisible=true
  19. Window #16 Window{abcabb9 u0 com.android.systemui.ImageWallpaper}://壁纸
  20. ty=WALLPAPER
  21. isOnScreen=false
  22. isVisible=false

一般手机都会存在以上 Window,层级顺序从高 -> 低。

显示PopWindow

  1.  Window #11 Window{513f711 u0 PopupWindow:3e4bfb}:
  2.    ty=APPLICATION_SUB_PANEL
  3.    isOnScreen=true
  4.    sVisible=true


显示Dialog

  1. Window #11 Window{a08f90b ...}:
  2.   ty=APPLICATION
  3.   isOnScreen=true
  4.   isVisible=true


不难看出,Window 层级与 ty 有关系的,ty 是 type 的简写。

Window 的分类

Application Window: 应用程序窗口

type 取值范围 [1,99]

  1. /**
  2. * Start of window types that represent normal application windows.
  3. */
  4. public static final int FIRST_APPLICATION_WINDOW = 1;
  5. // activity 会使用 此 type
  6. public static final int TYPE_BASE_APPLICATION = 1;
  7. // dialog 会使用 此 type
  8. public static final int TYPE_APPLICATION = 2;
  9. // 冷启动会显示的 Window,真正启动页面显示之前的画面
  10. public static final int TYPE_APPLICATION_STARTING = 3;
  11. // 没玩过
  12. public static final int TYPE_DRAWN_APPLICATION = 4;
  13. /**
  14. * End of types of application windows.
  15. */
  16. public static final int LAST_APPLICATION_WINDOW = 99;

Sub Window: 子窗口

子窗口:顾名思义,对应有主窗口。子窗口需要附在主窗口上,如PopWindow

type 取值范围 [1000,1999]

  1. /**
  2. * Start of types of sub-windows. The {@link #token} of these windows
  3. * must be set to the window they are attached to. These types of
  4. * windows are kept next to their attached window in Z-order, and their
  5. * coordinate space is relative to their attached window.
  6. */
  7. public static final int FIRST_SUB_WINDOW = 1000;
  8. public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
  9. public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;
  10. public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;
  11. public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;
  12. public static final int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4;
  13. public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;
  14. /**
  15. * End of types of sub-windows.
  16. */
  17. public static final int LAST_SUB_WINDOW = 1999;

System Window :系统窗口

type 取值范围 [2000,2999]

Toast,ANR 窗口,输入法,StatusBar,NavigationBar 等。

  1. /**
  2. * Start of system-specific window types. These are not normally
  3. * created by applications.
  4. */
  5. public static final int FIRST_SYSTEM_WINDOW = 2000;
  6. public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;
  7. public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;
  8. public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;
  9. /**
  10. * End of types of system windows.
  11. */
  12. public static final int LAST_SYSTEM_WINDOW = 2999;

之前好像看过文章说 type 值越大,层级越高,这个观点是错的

具体层级是下面逻辑代码,返回值越大,层级越高,最终在屏幕上显示时就越靠近用户。

  1. frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java
  2. /**
  3. * Returns the layer assignment for the window type. Allows you to control how different
  4. * kinds of windows are ordered on-screen.
  5. *
  6. * @param type The type of window being assigned.
  7. * @param canAddInternalSystemWindow If the owner window associated with the type we are
  8. * evaluating can add internal system windows. I.e they have
  9. * {@link Manifest.permission#INTERNAL_SYSTEM_WINDOW}. If true, alert window
  10. * types {@link android.view.WindowManager.LayoutParams#isSystemAlertWindowType(int)}
  11. * can be assigned layers greater than the layer for
  12. * {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} Else, their
  13. * layers would be lesser.
  14. * @param roundedCornerOverlay {#code true} to indicate that the owner window is rounded corner
  15. * overlay.
  16. * @return int An arbitrary integer used to order windows, with lower numbers below higher ones.
  17. */
  18. default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow,
  19. boolean roundedCornerOverlay) {
  20. // Always put the rounded corner layer to the top most.
  21. if (roundedCornerOverlay && canAddInternalSystemWindow) {
  22. return getMaxWindowLayer();
  23. }
  24. if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
  25. return APPLICATION_LAYER;// APPLICATION_LAYER = 2
  26. }
  27. switch (type) {
  28. case TYPE_WALLPAPER:
  29. // wallpaper is at the bottom, though the window manager may move it.
  30. return 1;
  31. case TYPE_PRESENTATION:
  32. case TYPE_PRIVATE_PRESENTATION:
  33. case TYPE_DOCK_DIVIDER:
  34. case TYPE_QS_DIALOG:
  35. case TYPE_PHONE:
  36. return 3;
  37. case TYPE_SEARCH_BAR:
  38. case TYPE_VOICE_INTERACTION_STARTING:
  39. return 4;
  40. case TYPE_VOICE_INTERACTION:
  41. // voice interaction layer is almost immediately above apps.
  42. return 5;
  43. case TYPE_INPUT_CONSUMER:
  44. return 6;
  45. case TYPE_SYSTEM_DIALOG:
  46. return 7;
  47. case TYPE_TOAST:
  48. // toasts and the plugged-in battery thing
  49. return 8;
  50. case TYPE_PRIORITY_PHONE:
  51. // SIM errors and unlock. Not sure if this really should be in a high layer.
  52. return 9;
  53. case TYPE_SYSTEM_ALERT:
  54. // like the ANR / app crashed dialogs
  55. // Type is deprecated for non-system apps. For system apps, this type should be
  56. // in a higher layer than TYPE_APPLICATION_OVERLAY.
  57. return canAddInternalSystemWindow ? 13 : 10;
  58. case TYPE_APPLICATION_OVERLAY:
  59. return 12;
  60. case TYPE_INPUT_METHOD:
  61. // on-screen keyboards and other such input method user interfaces go here.
  62. return 15;
  63. case TYPE_INPUT_METHOD_DIALOG:
  64. // on-screen keyboards and other such input method user interfaces go here.
  65. return 16;
  66. case TYPE_STATUS_BAR:
  67. return 17;
  68. case TYPE_STATUS_BAR_ADDITIONAL:
  69. return 18;
  70. case TYPE_NOTIFICATION_SHADE:
  71. return 19;
  72. case TYPE_STATUS_BAR_SUB_PANEL:
  73. return 20;
  74. case TYPE_KEYGUARD_DIALOG:
  75. return 21;
  76. case TYPE_VOLUME_OVERLAY:
  77. // the on-screen volume indicator and controller shown when the user
  78. // changes the device volume
  79. return 22;
  80. case TYPE_SYSTEM_OVERLAY:
  81. // the on-screen volume indicator and controller shown when the user
  82. // changes the device volume
  83. return canAddInternalSystemWindow ? 23 : 11;
  84. case TYPE_NAVIGATION_BAR:
  85. // the navigation bar, if available, shows atop most things
  86. return 24;
  87. case TYPE_NAVIGATION_BAR_PANEL:
  88. // some panels (e.g. search) need to show on top of the navigation bar
  89. return 25;
  90. case TYPE_SCREENSHOT:
  91. // screenshot selection layer shouldn't go above system error, but it should cover
  92. // navigation bars at the very least.
  93. return 26;
  94. case TYPE_SYSTEM_ERROR:
  95. // system-level error dialogs
  96. return canAddInternalSystemWindow ? 27 : 10;
  97. case TYPE_MAGNIFICATION_OVERLAY:
  98. // used to highlight the magnified portion of a display
  99. return 28;
  100. case TYPE_DISPLAY_OVERLAY:
  101. // used to simulate secondary display devices
  102. return 29;
  103. case TYPE_DRAG:
  104. // the drag layer: input for drag-and-drop is associated with this window,
  105. // which sits above all other focusable windows
  106. return 30;
  107. case TYPE_ACCESSIBILITY_OVERLAY:
  108. // overlay put by accessibility services to intercept user interaction
  109. return 31;
  110. case TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY:
  111. return 32;
  112. case TYPE_SECURE_SYSTEM_OVERLAY:
  113. return 33;
  114. case TYPE_BOOT_PROGRESS:
  115. return 34;
  116. case TYPE_POINTER:
  117. // the (mouse) pointer layer
  118. return 35;
  119. default:
  120. Slog.e("WindowManager", "Unknown window type: " + type);
  121. return 3;
  122. }
  123. }

以上方法,返回layer,type -> layer,以上代码可以得到如下信息。

layer 取值范围 【1,36】

App 对应 APPLICATION_LAYER,值为2,仅比 TYPE_WALLPAPER 大

Window 层级具体是怎么计算的呢?


从 System Window 中 基本已经找到答案。本章节具体说下实现细节:

mBaseLayer & mSubLayer
用来计算层级的两个参数

mSubLayer:用来计算子窗口的层级,默认值为0

mBaseLayer:用来计算主窗口的层级。

  1. frameworks/base/services/core/java/com/android/server/wm/WindowState.java
  2. if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
  3. mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
  4. * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;// layer * 10000 + 1000
  5. mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
  6. } else {
  7. mBaseLayer = mPolicy.getWindowLayerLw(this)
  8. * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;// layer * 10000 + 1000
  9. mSubLayer = 0;
  10. }

WindowState 中 mBaseLayer,mSubLayer

mBaseLayer:主窗口的 type 对应 value ,计算如下

如 Activity,type 是 TYPE_BASE_APPLICATION ,getWindowLayerLw 计算返回 APPLICATION_LAYER(2),mBaseLayer = 2 * 10000 + 1000

TYPE_LAYER_MULTIPLIER:为什么要 * 10000,将阈值扩大10000倍,系统中可能存在相同类型的窗口有很多。

TYPE_LAYER_OFFSET:为了移动同一层级的一组窗口

以上两个常量具体怎么使用,没有研究,该值不影响本文的分析。

mSubLayer:计算规则如下,取值范围 [-2,3],TYPE_APPLICATION_ATTACHED_DIALOG 值为 1,APPLICATION_MEDIA_SUBLAYER 值为 -2,看到这里就可以想到子窗口是可以在主窗口下方,主窗口如果可以看到子窗口,必须透明。
 

  1. frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java
  2. default int getSubWindowLayerFromTypeLw(int type) {
  3. switch (type) {
  4. case TYPE_APPLICATION_PANEL:
  5. case TYPE_APPLICATION_ATTACHED_DIALOG:
  6. return APPLICATION_PANEL_SUBLAYER;// 1
  7. case TYPE_APPLICATION_MEDIA:
  8. return APPLICATION_MEDIA_SUBLAYER;// -2
  9. case TYPE_APPLICATION_MEDIA_OVERLAY:
  10. return APPLICATION_MEDIA_OVERLAY_SUBLAYER;// -1
  11. case TYPE_APPLICATION_SUB_PANEL:
  12. return APPLICATION_SUB_PANEL_SUBLAYER; // 2
  13. case TYPE_APPLICATION_ABOVE_SUB_PANEL:
  14. return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER;// 3
  15. }
  16. Slog.e("WindowManager", "Unknown sub-window type: " + type);
  17. return 0;
  18. }

Sub Window 排序

  1. frameworks/base/services/core/java/com/android/server/wm/WindowState.java
  2. /**
  3. * Compares two window sub-layers and returns -1 if the first is lesser than the second in terms
  4. * of z-order and 1 otherwise.
  5. */
  6. private static final Comparator<WindowState> sWindowSubLayerComparator =
  7. new Comparator<WindowState>() {
  8. @Override
  9. public int compare(WindowState w1, WindowState w2) {
  10. final int layer1 = w1.mSubLayer;
  11. final int layer2 = w2.mSubLayer;
  12. if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0 )) {
  13. // We insert the child window into the list ordered by
  14. // the sub-layer. For same sub-layers, the negative one
  15. // should go below others; the positive one should go
  16. // above others.
  17. return -1;
  18. }
  19. return 1;
  20. };
  21. };

根据上文 mSubLayer 的值排序,如果是新插入的 window ,如果 sublayer 相等且为负值,放在下方,如果 sublayer 相等且为正值,放在上方。

主 Window 排序

  1. frameworks/base/services/core/java/com/android/server/wm/WindowToken.java
  2. /**
  3. * Compares two child window of this token and returns -1 if the first is lesser than the
  4. * second in terms of z-order and 1 otherwise.
  5. */
  6. private final Comparator<WindowState> mWindowComparator =
  7. (WindowState newWindow, WindowState existingWindow) -> {
  8. final WindowToken token = WindowToken.this;
  9. if (newWindow.mToken != token) {
  10. throw new IllegalArgumentException("newWindow=" + newWindow
  11. + " is not a child of token=" + token);
  12. }
  13. if (existingWindow.mToken != token) {
  14. throw new IllegalArgumentException("existingWindow=" + existingWindow
  15. + " is not a child of token=" + token);
  16. }
  17. return isFirstChildWindowGreaterThanSecond(newWindow, existingWindow) ? 1 : -1;
  18. };
  19. protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
  20. WindowState existingWindow) {
  21. // New window is considered greater if it has a higher or equal base layer.
  22. return newWindow.mBaseLayer >= existingWindow.mBaseLayer;
  23. }

与 Sub Window 排序类似,按照 mBaseLayer 大小排序,如果是新插入的,且相等,放在上方。

总结

主 window 排序图示

子 window 排序图示

 


————————————————
版权声明:本文为CSDN博主「Jingle.zhang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_58994853/article/details/125493914

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/325875
推荐阅读
相关标签
  

闽ICP备14008679号