你知道Android是如何管理复杂的Window层级的?
不知道开发者有没有发现,App上一直覆盖着StatusBar无论你怎么修改颜色,怎么写浮动框,都盖不住状态栏
框架开发,会有一些定制,比如覆盖StatusBar不知道的可能用错了,会有一些不必要的bug官方文件也没有列出窗口级别的规则
所以希望在下面和大家分享一下Android是如何制定显示层次规则的。
先说说Android中的Window这个概念。
其实很好理解就像经常使用Windows操作系统,打开一个应用,出现一个界面,我们可以理解为出现一个窗口,所以Window ≠ View
一个活动可以理解为对应一个窗口,懂源码的同学都知道ViewRootImpl对应一个窗口。
你觉得Window怎么样。
AdbshelldumpsysWindow选择了如下几个典型窗口:窗口# 2window911875cu0导航栏0://导航栏ty = navigation _ baris on screen = true visible = true Window # Window bf1a 956 u 0状态栏://状态栏ty = status _ baris on screen = true visible = true Window # 11 Window 377 AE 1 u 0输入法://输入法,不显示ty = input _ methodison screen = false可见= false窗口# 12 Window 190206 u 0
一般手机里都会有上面的窗口,层次顺序从高—gt,低。
显示弹出窗口
window # 11 window 513 f 711 u 0 popup window:3e 4 bfb:ty = LICATION _ SUB _ panelson screen = true visible = true
显示对话框
window # 11 window a08 f 90 b:ty = licionisonsource = true is visible = true
不难看出,窗口的级别与ty有关,ty是type的缩写。
Windows应用程序窗口的分类:应用程序窗口
类型值范围
/* * * Startofwindowtypesthatrepresentnormallicationwindows
子窗口:顾名思义,它对应于主窗口子窗口需要附加到主窗口,如PopWindow
类型值范围
/***Startoftypesofsub—windowsthe link # tokenofthewindows * mustbesettothewindowtheyarattachedto这些类型的* windowsarekeptnext to eirattacheddwindow in z—order,以及它们的* coordinate space is relativetotheattachedwindow*/publistaticfinalintfirst _ SUB _ WINDOW = 1000,publicstaticfinalintTYPE _ LICATION _ PANEL = FIRST _ SUB _ WINDOW,publicstaticfinalintTYPE _ LICATION _ MEDIA = FIRST _ SUB _ WINDOW+1,publistaticfinalinttype _ LICATION _ SUB _ PANEL = FIRST _ SUB _ WINDOW+2,publicstaticfinalintTYPE _ LICATION _ ATTACHED _ DIALOG = FIRST _ SUB _ WINDOW+3,publicstaticfinalintTYPE _ LICATION _ MEDIA _ OVERLAY = FIRST _ SUB _ WINDOW+4,publicstaticfinalintTYPE _ LICATION _ ABOVE _ SUB _ PANEL = FIRST _ SUB _ WINDOW+5,/***Endoftypesofsub窗口
类型值范围
比如吐司,ANR窗口,输入法,状态栏,导航条等。
/* * * Startofsystem—specificwindowtypes这些是不正常*创建的位置*/publistaticfinalintfirst _ SYSTEM _ WINDOW = 2000,publicstaticfinalintTYPE _ STATUS _ BAR = FIRST _ SYSTEM _ WINDOW,publicstaticfinalintTYPE _ SEARCH _ BAR = FIRST _ SYSTEM _ WINDOW+1,publistaticfinalinttype _ PHONE = FIRST _ SYSTEM _ WINDOW+2,/***Endoftypesofsystemwindows
之前好像看过一篇文章说类型值越大级别越高这种观点是错误的
具体级别是下面的逻辑代码返回值越大,级别越高,最终显示在屏幕上时离用户越近
frameworks/base/services/core/Java/com/Android/server/policy/windowmanagerpolicy . Java/* * * returnthelayerassignation for thewindowtypeallowshoutocontrolhowdifference * kindsofwindowsareorderedon—screen* * paramtypeThetypeofwindowbeingassigned* evaluatingcanaddinternalsystemwindows如果theownerwindow与thetypeweare关联*正在评估evaluatingcanaddinternalsystemwindowsI . etheyhave * link manifest . permission # INTERNAL _ SYSTEM _ WINDOW如果true,alert window * typeslink Android . view . window manager . layout params # isSystemAlertWindowType * canbeassignedlayers greaterthanthelayerfor * link Android . view . window manager . layout params # TYPE _ LICATION _ OVERLAYElse,their*layerswouldbelesser* paramcroundedcorneroverlay # codetruetoindicatehattheownerwindowwisroundedcorner * overlay*返回narbitraryintegerusedtoorderwindows,并带有lowernumbersbelowhigherones*/defaultintgetWindowLayerFromTypeLw//alwaysputtheroundedcornerlayertothtopmost . ifreturngetMaxWindowLayer,ifreturn LICATION _ LAYER,//LICATION _ LAYER = 2 switchcaseTYPE _ WALLPAPER://wallpaperisatthebottom,thoughthewindowmanagermaymoveit . return 1,caseTYPE _ PRESENTATION:caseTYPE _ PRIVATE _ PRESENTATION:caseTYPE _ DOCK _ DIVIDER:caseTYPE _ QS _ DIALOG:caseTYPE _ PHONE:return 3,caseTYPE _ SEARCH _ BAR:caseTYPE _ VOICE _ INTERACTION _ STARTING:return 4,caseTYPE _ VOICE _ INTERACTION://voiceinteractionlayerisalmostimitelyaborts . return 5,caseTYPE _ INPUT _ CONSUMER:return 6,caseTYPE _ SYSTEM _ DIALOG:return 7,caseTYPE _ TOAST://toastsandtheplugged—inbatterythingerunt 8,caseTYPE _ PRIORITY _ PHONE://SIMerrorsandunlocknotsurifthisreallyshouldbeinahighlayer . return 9,caseTYPE _ SYSTEM _ ALERT://likethenar/crashed dialogs//Typeisdeprecatedfornon—systems对于systems来说,thistype应该是//inahigherlayerthanTYPE _ LICATION _ overlay . returncanadinternalsystemwindow13:10,caseTYPE _ LICATION _ OVERLAY:return 12,caseTYPE _ INPUT _ METHOD://on—screen keyboardsandothersuchinputmethoduserinterfacesgohere . return 15,caseTYPE _ INPUT _ METHOD _ DIALOG://on—screen keyboardsandothersuchinputmethoduserinterfacesgohere . return 16,caseTYPE _ STATUS _ BAR:return 17,caseTYPE _ STATUS _ BAR _ ADDITIONAL:return 18,caseTYPE _ NOTIFICATION _ SHADE:return 19,caseTYPE _ STATUS _ BAR _ SUB _ PANEL:return 20,caseTYPE _ key guard _ DIALOG:return 21,caseTYPE _ VOLUME _ OVERLAY://theon—screenvolumeindicatorandcontrollershownwhentheuser//changesthedevicevolumereturn 22,caseTYPE _ SYSTEM _ OVERLAY://theon—screenvolumeindicatorandcontrollershownwhentheuser//changesthedevicevolumereturncandinternalsystemwindow23:11,caseTYPE _ NAVIGATION _ BAR://thenavigationbar,ifavailable,showsatopmostthingsreturn24caseTYPE _ NAVIGATION _ BAR _ PANEL://some panelsneedtoshowoontopofthenavigationbarreturn 25,caseTYPE _ screen shot selection layer should ' tgoabovesystemerror,butitshouldcover//navigationbarsattheverylest . return 26,caseTYPE _ SYSTEM _ ERROR://SYSTEM—level ERROR dialogsreturncanadinternalsystemwindow
上面的方法返回layer,type—gt,层,上面的代码可以得到以下信息。
层值范围
App _ layer的值是2,只比TYPE_WALLPAPER大。
窗位是如何计算的。
答案基本上已经从系统窗口找到了。本章具体描述了实施细节:
mBaseLayer ampmSubLayer
用于计算等级的两个参数
MSubLayer:用于计算子窗口的级别默认值为0
Selmbayer:用于计算主窗口的层次结构。
frameworks/base/services/core/Java/com/Android/server/WM/window state . javaifmattrs . type = FIRST _ SUB _ window amp,ampmattrs . TYPE = LAST _ SUB _ WINDOWmBaseLayer = m policy . getwindowlayerlw * TYPE _ LAYER _ MULTIPLIER+TYPE _ LAYER _ OFFSET,//layer * 10000+1000m sublayer = m policy . getsubwindowlayerfromtypelw,elsemBaseLayer = m policy . getwindowlayerlw* TYPE _ LAYER _ MULTIPLIER+TYPE _ LAYER _ OFFSET,//layer * 10000+1000m sublayer = 0,
MBaseLayer,WindowState中的mSubLayer
MBaseLayer:主窗口的类型对应于值,计算如下
例如Activity,类型为TYPE_BASE_APPLICATION,getWindowLayerLw计算返回APPLICATION_LAYER,mBaseLayer = 2 * 10000+1000。
TYPE_LAYER_MULTIPLIER:为什么* 10000把门槛放大10000倍系统中可能有许多相同类型的窗口
TYPE_LAYER_OFFSET:移动同一级别的一组窗口
以上两个常数如何使用还没有研究过,这个值不影响本文的分析。
MSubLayer:计算规则如下type _ APPLICATION _ attached _ dialog的值范围是1,APPLICATION_MEDIA_SUBLAYER的值范围是—2看到这里,你可以认为子窗口可以在主窗口下面如果你能看到子窗口,主窗口必须是透明的
frameworks/base/services/core/Java/com/Android/server/policy/windowmanagerpolicy . javadefaultintgetsubwindowlayerfromtypelwswitchcaseTYPE _ LICATION _ PANEL:caseTYPE _ LICATION _ ATTACHED _ DIALOG:returnLICATION _ PANEL _ SUBLAYER,//1 casetype _ LICATION _ MEDIA:return LICATION _ MEDIA _ SUBLAYER,//—2 casetype _ LICATION _ MEDIA _ OVERLAY:return LICATION _ MEDIA _ OVERLAY _ SUBLAYER,//—1 casetype _ LICATION _ SUB _ PANEL:return LICATION _ SUB _ PANEL _ SUBLAYER,//2 casetype _ LICATION _ ABOVE _ SUB _ PANEL:return LICATION _ ABOVE _ SUB _ PANEL _ SUBLAYER,//3Slog.e,return0子窗口排序
frameworks/base/services/core/Java/com/Android/server/WM/window state . Java/* * * Comparestwowindowsub—layer sandreturns—1 ifthefirstisslesserthanthesecondinterms * of z—order and 1 otherwise*/privatestaticfinalcomperator lt,WindowStategtswindowsublayercomprator = new comparator lt,WindowStategtoverridepublicintcomparefinalintlayer 1 = w1 . msublayer,finalintlayer2 = w2.mSubLayerifthrownewIllegalArgumentException,ifthrownewIllegalArgumentException,returnisfirstschildwindowgreaterthansecond
类似于子窗口排序,按照mBaseLayer大小排序如果是新插入的且相等,则放在顶部
摘要
主窗口排序图标
子窗口排序图标
郑重声明:此文内容为本网站转载企业宣传资讯,目的在于传播更多信息,与本站立场无关。仅供读者参考,并请自行核实相关内容。
责任编辑:杜玉梅