Android 12 S WindowManager解读之从dumpsys window windows看window

目录

适配刘海屏

窗口类型

窗口Flag

窗口Private Flag

System Bar Benhaviior

mBaseLayer 

mViewVisibility

Frames

mDrawState

DRAW_PENDING

COMMIT_DRAW_PENDING

READY_TO_SHOW

HAS_DRAWN


Status的代码如下,可以看到Status bar的很多窗口特征,我们以Status bar为例来看看dumpsys window的信息

/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java

    /**
     * Adds the status bar view to the window manager.
     */
    public void attach() {
        // Now that the status bar window encompasses the sliding panel and its
        // translucent backdrop, the entire thing is made TRANSLUCENT and is
        // hardware-accelerated.
        mLp = 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);
        mLpChanged.copyFrom(mLp);

        mContentInsetsProvider.addCallback(this::calculateStatusBarLocationsForAllRotations);
        calculateStatusBarLocationsForAllRotations();
    }

执行adb shell dumpsys window windows 如下:

  Window #3 Window{d2b0acf u0 StatusBar}://window名
    mDisplayId=0(display id,单屏一般都是0,多屏会有其他的比如1) rootTaskId=1(根Taskid) mSession=Session{e98843e 2512:u0a10120} mClient=android.os.BinderProxy@64c3da9
    mOwnerUid=10120 showForAllUsers=true package=com.android.systemui(package包名) appop=NONE
    mAttrs={(0,0)(fillx96) gr=TOP CENTER_VERTICAL(在顶端且居中)sim={adjust=pan}(view布局适配键盘)

//标志0 layoutInDisplayCutoutMode=always//标志1 ty=STATUS_BAR fmt=TRANSLUCENT
      //标志2 fl=NOT_FOCUSABLE SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
      //标志3 pfl=COLOR_SPACE_AGNOSTIC USE_BLAST FIT_INSETS_CONTROLLED
      //标志4 bhv=DEFAULT

      paramsForRotation={(0,0)(fillx96) gr=TOP CENTER_VERTICAL layoutInDisplayCutoutMode=always ty=STATUS_BAR fmt=TRANSLUCENT}}
    Requested w=7104 h=96 mLayoutSeq=2553
    //标志5 mBaseLayer=171000 mSubLayer=0    mToken=WindowToken{2f5ef2e android.os.BinderProxy@2471d30}
     //标志6 mViewVisibility=0x0 mHaveFrame=true mObscured=false
    mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]
    //当前config mFullConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw960dp w1776dp h876dp 640dpi xlrg long land vrheadset -touch -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 7104, 3840) mAppBounds=Rect(0, 0 - 7104, 3600) mMaxBounds=Rect(0, 0 - 7104, 3840) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} s.33 fontWeightAdjustment=0}
    //上一次的config mLastReportedConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw960dp w1776dp h876dp 640dpi xlrg long land vrheadset -touch -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 7104, 3840) mAppBounds=Rect(0, 0 - 7104, 3600) mMaxBounds=Rect(0, 0 - 7104, 3840) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} s.33 fontWeightAdjustment=0}
    mHasSurface=true(是否已创建Surface) isReadyForDisplay()=true(是否准备好要显示到屏幕上) mWindowRemovalAllowed=false
    //标志7 Frames: containing=[0,0][7104,3840] parent=[0,0][7104,3840] display=[0,0][7104,3840]
    mFrame=[0,0][7104,96] last=[0,0][7104,96]
     surface=[0,0][0,0]
    ContainerAnimator:
      mLeash=Surface(name=Surface(name=d2b0acf StatusBar)/@0x7ec48b - animation-leash of insets_animation)/@0x239f0e5 mAnimationType=insets_animation
      Animation: com.android.server.wm.InsetsSourceProvider$ControlAdapter@eab4059
        ControlAdapter mCapturedLeash=Surface(name=Surface(name=d2b0acf StatusBar)/@0x7ec48b - animation-leash of insets_animation)/@0x239f0e5
    WindowStateAnimator{1f471bd StatusBar}:
       mAnimationIsEntrance=true      mSurface=Surface(name=StatusBar)/@0x4ea33b2(Surface的名字)
      Surface: shown=true(surface是否已显示) layer=0 alpha=1.0 rect=(0.0,0.0)  transform=(1.0, 0.0, 0.0, 1.0)
      //标志8 mDrawState=HAS_DRAWN       mLastHidden=false
      mEnterAnimationPending=false      mSystemDecorRect=[0,0][0,0]
    mLastFreezeDuration=+268ms
    mForceSeamlesslyRotate=false seamlesslyRotate: pending=null finishedFrameNumber=0
    isOnScreen=true(是否在屏幕上)
    isVisible=true(是否可见)

适配刘海屏

标志0代表当前是怎么适配刘海屏的,Android 是允许您控制是否在刘海区域内显示内容的,有如下几种适配方式,您可以将 layoutInDisplayCutoutMode 设为以下某个值

layoutInDisplayCutoutMode的默认值是LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT。

layoutInDisplayCutoutMode
Value含义
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窗口总是可以扩展到刘海区域中

窗口类型

标志1代表当前的窗口类型,窗口总共三大类型,分别是Application类型, 子窗口类型,以及系统窗口类型:

窗口类型Vlaue含义
以下窗口类型为普通APPLICAT窗口类型,范围1-99
FIRST_APPLICATION_WINDOW 1App的初始值
TYPE_BASE_APPLICATION1所有App的基础值
TYPE_APPLICATION2普通应用程序窗口
TYPE_APPLICATION_STARTING3starting窗口
TYPE_DRAWN_APPLICATION4等待绘制完成的窗口
LAST_APPLICATION_WINDOW 99App的最大值
以下窗口类型为子窗口类型,范围1000-1999
FIRST_SUB_WINDOW 1000子窗口的初始值
TYPE_APPLICATION_PANELFIRST_SUB_WINDOW 应用程序窗口顶部的面板。这些窗口出现在它们的附属窗口的顶部。
TYPE_APPLICATION_MEDIAFIRST_SUB_WINDOW +1media子窗口
TYPE_APPLICATION_SUB_PANELFIRST_SUB_WINDOW +2子窗口之上的子窗口

TYPE_APPLICATION_ATTACHED

_DIALOG

FIRST_SUB_WINDOW +3Dialog子窗口

TYPE_APPLICATION_MEDIA

_OVERLAY

FIRST_SUB_WINDOW +4media子窗口之上的子窗口

TYPE_APPLICATION_ABOVE_

SUB_PANEL

FIRST_SUB_WINDOW +5在SUB_PANEL之上的子窗口
LAST_SUB_WINDOW 1999子窗口的最大值
以下为系统窗口类型,范围2000-2999
FIRST_SYSTEM_WINDOW2000系统窗口的初始值
TYPE_STATUS_BARFIRST_SYSTEM_WINDOW系统状态栏窗口
TYPE_SEARCH_BARFIRST_SYSTEM_WINDOW+1搜索条窗口
TYPE_PHONEFIRST_SYSTEM_WINDOW+2通话窗口,位于状态栏之上
TYPE_SYSTEM_ALERTFIRST_SYSTEM_WINDOW+3Alert窗口,如电量不足提示,显示在APP之上窗口
TYPE_KEYGUARDFIRST_SYSTEM_WINDOW+4锁屏窗口
TYPE_TOASTFIRST_SYSTEM_WINDOW+5短暂的提示框窗口
TYPE_SYSTEM_OVERLAYFIRST_SYSTEM_WINDOW+6系统覆盖窗口,不能接受input焦点,否则会与屏保发生冲突
TYPE_PRIORITY_PHONEFIRST_SYSTEM_WINDOW+7电话优先窗口,如屏保状态下显示来电窗口
TYPE_SYSTEM_DIALOGFIRST_SYSTEM_WINDOW+8系统Dialog窗口
TYPE_KEYGUARD_DIALOGFIRST_SYSTEM_WINDOW+9keyguard Dialog窗口
TYPE_SYSTEM_ERRORFIRST_SYSTEM_WINDOW+10系统报错窗口
TYPE_INPUT_METHODFIRST_SYSTEM_WINDOW+11输入法窗口
TYPE_INPUT_METHOD_DIALOGFIRST_SYSTEM_WINDOW+12输入法Dialog窗口
TYPE_WALLPAPERFIRST_SYSTEM_WINDOW+13壁纸窗口
TYPE_STATUS_BAR_PANELFIRST_SYSTEM_WINDOW+14从状态栏滑出的面板在多用户系统中显示在所有用户的窗口上。

TYPE_SECURE_SYSTEM_OVERLAY

FIRST_SYSTEM_WINDOW+15@hide
TYPE_DRAGFIRST_SYSTEM_WINDOW+16@hide拖拽窗口

TYPE_STATUS_BAR_SUB_PANEL

FIRST_SYSTEM_WINDOW+17@hide,status bar之上的子窗口
TYPE_POINTERFIRST_SYSTEM_WINDOW+18@hide
TYPE_NAVIGATION_BARFIRST_SYSTEM_WINDOW+19@hide导航栏窗口
TYPE_VOLUME_OVERLAYFIRST_SYSTEM_WINDOW+20@hide系统音量条
TYPE_BOOT_PROGRESSFIRST_SYSTEM_WINDOW+21@hide启动时的进度条窗口
TYPE_INPUT_CONSUMERFIRST_SYSTEM_WINDOW+22@hide消耗input事件的窗口
TYPE_NAVIGATION_BAR_PANELFIRST_SYSTEM_WINDOW+24@hide
TYPE_DISPLAY_OVERLAYFIRST_SYSTEM_WINDOW+26@hide用于模拟第二个Display显示屏
TYPE_MAGNIFICATION_OVERLAYFIRST_SYSTEM_WINDOW+27@hide
TYPE_PRIVATE_PRESENTATIONFIRST_SYSTEM_WINDOW+30
TYPE_VOICE_INTERACTIONFIRST_SYSTEM_WINDOW+31@hide
TYPE_ACCESSIBILITY_OVERLAYFIRST_SYSTEM_WINDOW+32

TYPE_VOICE_INTERACTION_STARTING

FIRST_SYSTEM_WINDOW+33@hide
TYPE_DOCK_DIVIDERFIRST_SYSTEM_WINDOW+34@hide
TYPE_QS_DIALOGFIRST_SYSTEM_WINDOW+35@hide
TYPE_SCREENSHOTFIRST_SYSTEM_WINDOW+36@hide在锁屏之上,该层保留截图动画,区域选择和UI。
TYPE_PRESENTATIONFIRST_SYSTEM_WINDOW+37@hide用于在外部显示器上显示的窗口(多个屏幕情况下)
TYPE_APPLICATION_OVERLAYFIRST_SYSTEM_WINDOW+38

TYPE_ACCESSIBILITY_MAGNIFICATION

_OVERLAY

FIRST_SYSTEM_WINDOW+39@hide
TYPE_NOTIFICATION_SHADEFIRST_SYSTEM_WINDOW+40@hide
TYPE_STATUS_BAR_ADDITIONALFIRST_SYSTEM_WINDOW+41@hide
LAST_SYSTEM_WINDOW2999系统窗口的最大值

窗口Flag

标志2地方的意思是窗口所携带的 flag,这个指的这个这个window 所携带的flag, 窗口的flag如下

序号FLAG作用
1FLAG_ALLOW_LOCK_WHILE_SCREEN_ON0x00000001只要该window可见,允许屏幕开启的时候锁屏
2FLAG_DIM_BEHIND0x00000002所有在携带这个flag的window后面的窗口都会变暗
3FLAG_BLUR_BEHIND0x00000004为这个窗口启用后面模糊。
4FLAG_NOT_FOCUSABLE0x00000008该window不能获取焦点
5FLAG_NOT_TOUCHABLE0x00000010该window不能触摸
6FLAG_NOT_TOUCH_MODAL0x00000020无模式窗口,在该窗口区域外的pointer时间将传给它后面的其他窗口,而不是由它自己处理
7FLAG_TOUCHABLE_WHEN_WAKING0x00000040当设备进入睡眠状态时,设置此标志可以使你获取第一次触摸事件(因为这时候用户不并不知道他们点击的是屏幕上的哪个位置,所以通畅这一世间是由系统自动处理的)
8FLAG_KEEP_SCREEN_ON0x00000080只要这个窗口可见,屏幕将保持常亮
9FLAG_LAYOUT_IN_SCREEN0x00000100窗口显示时不考虑系统装饰窗eg, statusbar
10FLAG_LAYOUT_NO_LIMITS0x00000200允许窗口超出屏幕区域
11FLAG_FULLSCREEN0x00000400隐藏所有的装饰窗口窗口,如statusbar
12FLAG_FORCE_NOT_FULLSCREEN0x00000800和上面的标志相反
13FLAG_DITHER0x00001000将此窗口合成到屏幕时,打开抖动。丢弃
14FLAG_SECURE0x00002000窗口内容被认为是保密的,所以它无法出现在截屏中,不安全的屏幕上也无法显示
15FLAG_SCALED0x00004000按照用户提供的参数做伸缩调整
16FLAG_IGNORE_CHEEK_PRESSES0x00008000有的时候用户会和屏幕贴的很近,如打电话,这种情况下出现的某些事件可能是无意的,不应该相应
17FLAG_LAYOUT_INSET_DECOR0x00010000只能和FLAG_LAYOUT_IN_SCREEN一起使用,当设置了全屏显示布局时,应用窗口部分内容仍然可能被系统装饰窗口覆盖,如果同时设置了这一标志时,系统将充分考虑系统窗口所占的区域,以防出现上述情况。
18FLAG_ALT_FOCUSABLE_IM0x00020000设置后,反转窗口的输入法聚焦性。设置此标志的效果取决于是否设置了#FLAG_NOT_FOCUSABLE
19FLAG_WATCH_OUTSIDE_TOUCH0x00040000该值配合FLAG_NOT_TOUCH_MODAL才会生效,代表该window以外的区域也是可以接收key的
20FLAG_SHOW_WHEN_LOCKED0x00080000使窗口可以显示在锁屏之上
21FLAG_SHOW_WALLPAPER0x00100000让壁纸在这个窗口之后显示,当窗口是透明后或者半透明的时候,可以看到后面的壁纸
22FLAG_TURN_SCREEN_ON0x00200000窗口显示时将屏幕点亮,如来电界面
23FLAG_DISMISS_KEYGUARD0x00400000窗口显示时,将解锁屏幕锁,只是它不是一个secure lock
24FLAG_SPLIT_TOUCH0x00800000当设置时,窗口将接受超出其边界的触摸事件发送到其他支持拆分触摸的窗口。当这个标志没有设置时,第一个向下的指针决定了所有后续触摸的窗口,直到所有指针向上。当设置这个标志时,每个指针(不一定是第一个)向下的指针决定了该指针的所有后续触摸将进入的窗口,直到该指针向上为止,从而使具有多个指针的触摸可以在多个窗口中分割。
25FLAG_HARDWARE_ACCELERATED0x01000000启动硬件加速,但加了该flag并不一定保证窗口一定能得到硬件加速
26FLAG_LAYOUT_IN_OVERSCAN0x02000000允许窗口内容扩展到屏幕的扫描区域(如果有的话)。窗口仍然应该正确定位其内容,以考虑过扫描区域。这个标志可以在你的主题中通过android.R.attr #windowOverscan属性来控制;该属性是在标准监视主题中自动为您设置的
27FLAG_TRANSLUCENT_STATUS0x04000000请求一个半透明的状态栏与最小的系统提供的背景保护。这个标志可以在你的主题中通过android.R.attr #windowTranslucentStatus属性来控制;这个属性是在标准半透明装饰主题中自动设置的
28FLAG_TRANSLUCENT_NAVIGATION0x08000000请求一个半透明的导航栏与最小的系统提供的背景保护。这个标志可以在你的主题中通过android.R.attr #windowTranslucentNavigation属性来控制;这个属性是在标准半透明装饰主题中自动设置的
29FLAG_LOCAL_FOCUS_MODE0x10000000本地焦点模式下窗口的标志。本地焦点模式下的窗口可以使用window# setLocalFocus (boolean, boolean)}独立于窗口管理器控制焦点。
30FLAG_SLIPPERY0x20000000允许触摸在手势的中间从窗口滑到相邻的窗口,而不是在手势的持续时间内被捕获。这个标志只改变了这个窗口的触摸焦点行为。触摸可以滑出窗口,但不一定滑回来(除非另一个有触摸焦点的窗口允许)。
31FLAG_LAYOUT_ATTACHED_IN_DECOR0x40000000当请求带有附属窗口的布局时,附属窗口可能与父窗口的屏幕装饰重叠,例如导航栏。通过包含此标志,窗口管理器将在父窗口的装饰框架内布局附加的窗口,这样它就不会与屏幕装饰重叠。
32FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS0x80000000表明该窗口负责绘制系统栏的背景。如果设置了,系统栏将使用透明背景绘制,并且该窗口中的相应区域将使用window # getStatusBarColor()}和window #getNavigationBarColor()}中指定的颜色填充。

窗口Private Flag

标志3处也是窗口的一些Flag特征,只不过这些Flag都添加有@hide的,所以是不对外暴露的,所以应用是无法添加这些flag的。

PRIVATE_FLAG含义
PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED0x00000002在系统进程中,我们全局不使用硬件加速,因为有很多线程在那里做UI,它们会发生冲突。如果UI的某些部分确实想要使用硬件加速,则可以设置此标志来强制使用。这基本上是用于锁屏的。如果有人用它,你可能错了
PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS0x00000004默认情况下,壁纸滚动时壁纸会发送新的偏移,壁纸可以通过调用方法来选择跳过这些通知
PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY0x00000008
SYSTEM_FLAG_SHOW_FOR_ALL_USERS0x00000010在多用户系统中,如果设置了这个标志,并且所有者是一个系统进程,那么这个窗口将出现在所有用户屏幕上。这将覆盖通常只出现在拥有用户屏幕上的窗口类型的默认行为。请参考每个窗口类型以确定其默认行为。
PRIVATE_FLAG_NO_MOVE_ANIMATION0x00000040永远不要让窗口的位置变化产生动画效果。
PRIVATE_FLAG_COMPATIBLE_WINDOW0x00000080限制窗口大小为原始大小的特殊标志([320x480] x密度)。用于为在兼容模式下运行的应用程序创建窗口
PRIVATE_FLAG_SYSTEM_ERROR0x00000100用于系统对话框的特殊选项。当设置此标志时,窗口将在创建时无条件地要求焦点。
PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS0x00000800防止当前窗口后面的墙纸接收触摸事件的标志。
PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR0x00001000强制状态栏窗口始终可见。如果设置此标志时该栏被隐藏,则会再次显示。它只在 LayoutParams # TYPE_STATUS_BAR设置时生效。
PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY0x00004000使窗口忽略应用可见性。而完全依赖于decor视图可见性来确定窗口可见性。这是recents在启动应用程序后用来继续绘图的。
PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH0x00008000指示该窗口不会在配置更改触发的活动重新启动时被替换。通常,WindowManager期望在重新启动后替换Windows,因此它将保留其surfaces,直到替换准备显示,以防止视觉故障。然而,一些窗口,如PopupWindows期望在配置更改时被清除,因此应该提示WindowManager它不应该等待替换。

PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN

_PARENT_FRAME

0x00010000表示无论当前的窗口模式配置如何,该子窗口应始终布局在父框架中
PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS0x00020000表示无论其他标志是什么,该窗口总是绘制状态栏背景。
PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE0x00040000如果设备支持,表示此窗口需要持续性能模式的标志。

SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY

_WINDOWS

0x00080000表示任何由应用程序进程添加的窗口类型为TYPE_TOAST或需要@link android.app。
PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY0x00100000此窗口是某些设备上存在的圆角覆盖,这意味着它将被排除在:屏幕截图,屏幕放大和镜像中。
PRIVATE_FLAG_NOT_MAGNIFIABLE0x00400000防止窗口被辅助功能放大器放大。
PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION0x00800000表示状态栏窗口处于强制显示导航栏的状态,除非导航栏窗口显式地设置为view# GONE,它只在 LayoutParams # TYPE_STATUS_BAR设置时生效。
PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC0x01000000表示该窗口与颜色空间无关,并且该颜色可以解释到任何颜色空间。
PRIVATE_FLAG_USE_BLAST0x02000000请求创建一个BLAST (Buffer as LayerState)层的标志。
如果没有指定,客户端将接收一个BufferQueue层。
PRIVATE_FLAG_APPEARANCE_CONTROLLED0x04000000表明窗口正在控制系统栏的外观。所以我们不需要通过读取它的系统UI标志来调整它的兼容性。
PRIVATE_FLAG_BEHAVIOR_CONTROLLED0x08000000表明窗口正在控制系统栏的行为。因此,我们不需要通过读取其窗口标志或系统UI标志来调整它的兼容性。
PRIVATE_FLAG_FIT_INSETS_CONTROLLED0x10000000指示窗口自己控制如何适应窗口插入。所以我们不需要调整它的属性来适应窗口的嵌套。
PRIVATE_FLAG_TRUSTED_OVERLAY0x20000000表明窗口是受信任的覆盖层
PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME0x40000000表示窗口的父框架应该由IME插入。

PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG

_AND_DROP

0x80000000

表示我们想要拦截和处理所有用户的全局拖放操作。

此标志允许考虑窗口的拖动事件,即使不可见,并且将接收系统中所有活动用户的拖动。

附加数据提供给带有此标志的窗口,包括{@link ClipData},包括所有带有DragEvent # ACTION_DRAG_STARTED}事件的项目,以及带有DragEvent # ACTION_DROP}事件的实际拖拽面。如果窗口消耗了拖放,那么拖放表面的清理(作为DragEvent # ACTION_DROP的一部分提供)将被交给窗口。

System Bar Benhaviior

标志4用于描述System Bar的行为

System Bar BenhaviiorValue含义
BEHAVIOR_SHOW_BARS_BY_TOUCH0

可通过setSystemBarsBehavior进行设置。

如果导航栏被#hide(int)或setsetsandalpha (Insets, float, float)隐藏,系统栏将被强制显示在任何用户交互的相应显示器上。@deprecated在Android S和更高版本上不支持。

使用#BEHAVIOR_DEFAULT或# BEHAVIOR_SHOW_
TRANSIENT
_BARS_BY_SWIPE代替。

BEHAVIOR_DEFAULT1

可通过setSystemBarsBehavior进行设置。窗口希望通过调用#hide(int)或#setInsetsAndAlpha (Insets, float, float)}来隐藏导航条时保持交互。

当系统栏在此模式下隐藏时,可以通过系统手势显示它们,例如从隐藏栏的屏幕边缘滑动。

启用手势导航后,无论系统栏是否可见,都可以触发系统手势。

BEHAVIOR_SHOW_BARS_BY_SWIPE

BEHAVIOR

_DEFAULT

可通过setSystemBarsBehavior进行设置。窗口希望通过调用#hide(int)或#setInsetsAndAlpha (Insets, float, float)}隐藏导航栏时保持交互。

当系统栏在此模式下隐藏时,可以通过系统手势显示它们,例如从隐藏栏的屏幕边缘滑动。

使用#BEHAVIOR_DEFAULT代替。

BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE2

可通过setSystemBarsBehavior进行设置。窗口希望通过调用#hide(int)或#setInsetsAndAlpha (Insets, float, float)}隐藏导航栏时保持交互。

当系统栏在此模式下隐藏时,可以通过系统手势暂时显示它们,例如从隐藏栏的屏幕边缘滑动。这些短暂的系统条将覆盖应用程序的内容,可能有一定程度的透明度,并在短暂的超时后自动隐藏。

mBaseLayer 

  标志5 mBaseLayer,代表窗口的layer层级,根据窗口Type转化而来,代码如下:

    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) {

                 ......

        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;
        }
    default int getWindowLayerFromTypeLw(int type) {
        if (isSystemAlertWindowType(type)) {
            throw new IllegalArgumentException("Use getWindowLayerFromTypeLw() or"
                    + " getWindowLayerLw() for alert window types");
        }
        return getWindowLayerFromTypeLw(type, false /* canAddInternalSystemWindow */);
    }
    default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) {
        return getWindowLayerFromTypeLw(type, canAddInternalSystemWindow,
                false /* roundedCornerOverlay */);
}
    /**
     * 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_APPLICATION_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_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;
        }
    }

 整理成表格,则如下:

窗口类型Layer值
FIRST_APPLICATION_WINDOWAPPLICATION_LAYER=2
LAST_APPLICATION_WINDOW
TYPE_WALLPAPER1
TYPE_PRESENTATION3
TYPE_PRIVATE_PRESENTATION
TYPE_DOCK_DIVIDER
TYPE_QS_DIALOG
TYPE_PHONE
TYPE_SEARCH_BAR4
TYPE_VOICE_INTERACTION_STARTING
TYPE_VOICE_INTERACTION5
TYPE_INPUT_CONSUMER6
TYPE_SYSTEM_DIALOG7
TYPE_TOAST8
TYPE_PRIORITY_PHONE9
TYPE_SYSTEM_ALERTcanAddInternalSystemWindow ? 13 : 10;
TYPE_APPLICATION_OVERLAY12
TYPE_INPUT_METHOD15
TYPE_INPUT_METHOD_DIALOG16
TYPE_STATUS_BAR17
TYPE_STATUS_BAR_ADDITIONAL18
TYPE_NOTIFICATION_SHADE19
TYPE_STATUS_BAR_SUB_PANEL20
TYPE_KEYGUARD_DIALOG21
TYPE_VOLUME_OVERLAY22
TYPE_SYSTEM_OVERLAYcanAddInternalSystemWindow ? 23 : 11;
TYPE_NAVIGATION_BAR24
TYPE_NAVIGATION_BAR_PANEL25
TYPE_SCREENSHOT26
TYPE_SYSTEM_ERROR27
TYPE_MAGNIFICATION_OVERLAY28
TYPE_DISPLAY_OVERLAY29
TYPE_DRAG30
TYPE_ACCESSIBILITY_OVERLAY31
TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY32
TYPE_SECURE_SYSTEM_OVERLAY33
TYPE_BOOT_PROGRESS34
TYPE_POINTER35
default3

 这些值得到后还要在进行如下计算才可以:

mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
                    * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;

//将策略的类型层乘以多少,为相同类型的多个窗口保留空间,并使用TYPE_LAYER_OFFSET调整z顺序
    static final int TYPE_LAYER_MULTIPLIER = 10000;

//TYPE_LAYER_MULTIPLIER的偏移量,用于在同一层中移动一组窗口的上方或下方
    static final int TYPE_LAYER_OFFSET = 1000;

mViewVisibility

标志6代表当前View的可见性

mViewVisibilityVlaue含义
VISIBLE0x00000000

这个视图可见

与#setVisibility和#attr_android:visibility" android:visibility}一起使用。

INVISIBLE0x00000004

这个视图不可见

与#setVisibility和#attr_android:visibility" android:visibility}一起使用。

GONE0x00000008

这个视图是不可见的,它不占用任何空间进行布局

与#setVisibility和#attr_android:visibility" android:visibility}一起使用。

Frames

标志7代表当前window的各种区域描述

    public void dump(PrintWriter pw, String prefix) {
        pw.println(prefix + "Frames: containing="
                + mContainingFrame.toShortString(sTmpSB)
                + " parent=" + mParentFrame.toShortString(sTmpSB)
                + " display=" + mDisplayFrame.toShortString(sTmpSB));
        pw.println(prefix + "mFrame=" + mFrame.toShortString(sTmpSB)
                + " last=" + mLastFrame.toShortString(sTmpSB));
    }
    /**
     * In most cases, this is the area of the entire screen.
     * 在大多数情况下,这是整个屏幕的面积。
     */
    public final Rect mParentFrame = new Rect();

    /**
     * The entire screen area of the {@link Task} this window is in. Usually equal to the screen area of the device.
     */此窗口所在的Task的整个屏幕区域。通常等于设备的屏幕面积。
    public final Rect mDisplayFrame = new Rect();

    /**
     * Similar to {@link #mDisplayFrame}
     */
    final Rect mContainingFrame = new Rect();

    /**
     * "Real" frame that the application sees, in display coordinate space.
     */应用程序在显示坐标空间中看到的“真实”帧。
    final Rect mFrame = new Rect();

    /**
     * The last real frame that was reported to the client.
     */报告给客户端的最后一个真实帧。
    final Rect mLastFrame = new Rect();

    /**
     * mFrame but relative to the parent container.
     */mFrame,但相对于父容器。
    final Rect mRelFrame = new Rect();

    /**
     * mLastFrame but relative to the parent container
     */mLastFrame,但相对于父容器
    final Rect mLastRelFrame = new Rect();

mDrawState

标志8代表当前窗口的绘制状态

绘制总共有以下几种状态

mDrawStateValue含义
NO_SURFACE0当没有Surface时设置
DRAW_PENDING1这是在创建Surface之后,但在绘制窗口之前设置的。在此期间,Surface是hidden的。
COMMIT_DRAW_PENDING2这是在窗口第一次完成绘图之后,但在其Surface显示之前设置的。当运行下一个布局时,将显示该Surface。
READY_TO_SHOW3这是在提交窗口绘图之后,在其Surface实际显示之前设置的。它用于延迟显示Surface,直到令牌中的所有窗口都准备好显示为止。
HAS_DRAWN4当窗口第一时间被显示在屏幕上时设置

这几种状态的时机分别是什么时候呢,是怎么变化直至显示到屏幕上的呢,让我们捋一下代码。

DRAW_PENDING

这个状态下,Surface已经创建,但还未开始绘制窗口。在此期间,这个Surface是hidden的。

 第一种情况

当系统中没有这个Surface时,要去创建的时候,create Surface时

其状态应该是从NO_SURFACE -> DRAW_PENDING

frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java 

    WindowSurfaceController createSurfaceLocked(int windowType) {
        final WindowState w = mWin;

        if (mSurfaceController != null) {
            return mSurfaceController;
        }

        w.setHasSurface(false);

        if (DEBUG_ANIM) {
            Slog.i(TAG, "createSurface " + this + ": mDrawState=DRAW_PENDING");
        }

        resetDrawState();
        ......
    }
    void resetDrawState() {
        mDrawState = DRAW_PENDING;

        if (mWin.mActivityRecord == null) {
            return;
        }

        if (!mWin.mActivityRecord.isAnimating(TRANSITION)) {
            mWin.mActivityRecord.clearAllDrawn();
        }
    }

第二种情况

如果window的size或者config发生变化时会重新绘制界面

    void updateResizingWindowIfNeeded() {
        final WindowStateAnimator winAnimator = mWinAnimator;
        if (!mHasSurface || getDisplayContent().mLayoutSeq != mLayoutSeq || isGoneForLayout()) {
            return;
        }

        boolean didFrameInsetsChange = setReportResizeHints();
        // The latest configuration will be returned by the out parameter of relayout, so it is unnecessary to report resize if this window is running relayout.
        final boolean configChanged = !mInRelayout && !isLastConfigReportedToClient();
        if (DEBUG_CONFIGURATION && configChanged) {
            Slog.v(TAG_WM, "Win " + this + " config changed: " + getConfiguration());
        }

        final boolean dragResizingChanged = isDragResizeChanged()
                && !isDragResizingChangeReported();

        if (DEBUG) {
            Slog.v(TAG_WM, "Resizing " + this + ": configChanged=" + configChanged
                    + " dragResizingChanged=" + dragResizingChanged
 + " last=" + mWindowFrames.mLastFrame + " frame=" + mWindowFrames.mFrame);
        }

        // We update mLastFrame always rather than in the conditional with the last inset variables, because mFrameSizeChanged only tracks the width and height changing.
        updateLastFrames();

        // Add a window that is using blastSync to the resizing list if it hasn't been reported already. This because the window is waiting on a finishDrawing from the client.
        if (didFrameInsetsChange
                || configChanged
                || dragResizingChanged
                || mReportOrientationChanged
                || shouldSendRedrawForSync()) {
            ProtoLog.v(WM_DEBUG_RESIZE,
  "Resize reasons for w=%s:  %s configChanged=%b "
 + "dragResizingChanged=%b reportOrientationChanged=%b",
  this, mWindowFrames.getInsetsChangedInfo(),
 configChanged, dragResizingChanged, mReportOrientationChanged);

            // If it's a dead window left on screen, and the configuration changed, there is nothing. we can do about it. Remove the window now.
            if (mActivityRecord != null && mAppDied) {
                mActivityRecord.removeDeadWindows();
                return;
            }

            onResizeHandled();
            mWmService.makeWindowFreezingScreenIfNeededLocked(this);

            // If the orientation is changing, or we're starting or ending a drag resizing action, then we need to hold off on unfreezing the display until this window has been redrawn; to do that, we need to go through the process of getting informed by the application when it has finished drawing.
            if (getOrientationChanging() || dragResizingChanged) {
                if (dragResizingChanged) {
                    ProtoLog.v(WM_DEBUG_RESIZE,
 "Resize start waiting for draw, " + "mDrawState=DRAW_PENDING in %s, surfaceController %s", this, winAnimator.mSurfaceController);
                }
                winAnimator.mDrawState = DRAW_PENDING;
                if (mActivityRecord != null) {
                    mActivityRecord.clearAllDrawn();
                }
            }
            if (!mWmService.mResizingWindows.contains(this)) {
                ProtoLog.v(WM_DEBUG_RESIZE, "Resizing window %s", this);
                mWmService.mResizingWindows.add(this);
            }
        } else if (getOrientationChanging()) {
            if (isDrawn()) {
                ProtoLog.v(WM_DEBUG_ORIENTATION,
                        "Orientation not waiting for draw in %s, surfaceController %s", this, winAnimator.mSurfaceController);
                setOrientationChanging(false);
                mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
                        - mWmService.mDisplayFreezeTime);
            }
        }
    }

 第三种情况

    /** @see WindowManagerInternal#waitForAllWindowsDrawn */
    void requestDrawIfNeeded(List<WindowState> outWaitingForDrawn) {
        if (!isVisible()) {
            return;
        }
        if (mActivityRecord != null) {
            if (mActivityRecord.allDrawn) {
                // The allDrawn of activity is reset when the visibility is changed to visible, so
                // the content should be ready if allDrawn is set.
                return;
            }
            if (mAttrs.type == TYPE_APPLICATION_STARTING) {
                if (isDrawn()) {
                    // Unnecessary to redraw a drawn starting window.
                    return;
                }
            } else if (mActivityRecord.mStartingWindow != null) {
                // If the activity has an active starting window, there is no need to wait for the
                // main window.
                return;
            }
        } else if (!mPolicy.isKeyguardHostWindow(mAttrs)) {
            return;
            // Always invalidate keyguard host window to make sure it shows the latest content
            // because its visibility may not be changed.
        }

        mWinAnimator.mDrawState = DRAW_PENDING;
        // Force add to {@link WindowManagerService#mResizingWindows}.
        forceReportingResized();
        outWaitingForDrawn.add(this);
    }

COMMIT_DRAW_PENDING

这个状态下窗口已经绘制完成,但还未被设置为Visable状态。

DRAW_PENDING -> COMMIT_DRAW_PENDING

    boolean finishDrawingLocked(SurfaceControl.Transaction postDrawTransaction) {
        final boolean startingWindow =
                mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
        if (startingWindow) {
            ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finishing drawing window %s: mDrawState=%s",  mWin, drawStateToString());
        }

        boolean layoutNeeded = false;

        if (mDrawState == DRAW_PENDING) {
            ProtoLog.v(WM_DEBUG_DRAW, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s", mWin, mSurfaceController);
            if (startingWindow) {
                ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Draw state now committed in %s", mWin);
            }
            mDrawState = COMMIT_DRAW_PENDING;
            layoutNeeded = true;
        }

        if (postDrawTransaction != null) {
            // If there is no surface, the last draw was for the previous surface. We don't want to wait until the new surface is shown and instead just apply the transaction right away.
            if (mLastHidden && mDrawState != NO_SURFACE) {
                mPostDrawTransaction.merge(postDrawTransaction);
                layoutNeeded = true;
            } else {
                postDrawTransaction.apply();
            }
        }

        return layoutNeeded;
    }

READY_TO_SHOW

这个时候窗口已经完成绘图,但是其Surface还未设置为实状态际显示。它用于延迟显示Surface,直到tokens中的所有窗口都准备好显示为止。

COMMIT_DRAW_PENDING ->READY_TO_SHOW

    // This must be called while inside a transaction.
    boolean commitFinishDrawingLocked() {
        if (DEBUG_STARTING_WINDOW_VERBOSE &&
                mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
            Slog.i(TAG, "commitFinishDrawingLocked: " + mWin + " cur mDrawState="
                    + drawStateToString());
        }
        if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
            return false;
        }
        if (DEBUG_ANIM) {
            Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurfaceController);
        }
        mDrawState = READY_TO_SHOW;
        boolean result = false;
        final ActivityRecord activity = mWin.mActivityRecord;
        if (activity == null || activity.canShowWindows()
                || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
//这个会走入HAS_DRAWN所在的函数的逻辑
            result = mWin.performShowLocked();
        }
        return result;
    }

HAS_DRAWN

这个时候窗口已经绘制完成,并准备好要显示了,

READY_TO_SHOW -> HAS_DRAWN

    boolean performShowLocked() {
        if (!showToCurrentUser()) {
            if (DEBUG_VISIBILITY) Slog.w(TAG, "hiding " + this + ", belonging to " + mOwnerUid);
            clearPolicyVisibilityFlag(VISIBLE_FOR_USER);
            return false;
        }

        logPerformShow("performShow on ");

        final int drawState = mWinAnimator.mDrawState;
        if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW) && mActivityRecord != null) {
            if (mAttrs.type != TYPE_APPLICATION_STARTING) {
               //窗口要显示了,所以要移除STARTING_WINDOW
                mActivityRecord.onFirstWindowDrawn(this, mWinAnimator);
            } else {
                mActivityRecord.onStartingWindowDrawn();
            }
        }

        if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
            return false;
        }

        logPerformShow("Showing ");

        mWmService.enableScreenIfNeededLocked();
        mWinAnimator.applyEnterAnimationLocked();

        // Force the show in the next prepareSurfaceLocked() call.
        mWinAnimator.mLastAlpha = -1;
        if (DEBUG_ANIM) Slog.v(TAG,
                "performShowLocked: mDrawState=HAS_DRAWN in " + this);
        mWinAnimator.mDrawState = HAS_DRAWN;
        //执行窗口动画
        mWmService.scheduleAnimationLocked();

        if (mHidden) {
            mHidden = false;
            final DisplayContent displayContent = getDisplayContent();

            for (int i = mChildren.size() - 1; i >= 0; --i) {
                final WindowState c = mChildren.get(i);
                if (c.mWinAnimator.mSurfaceController != null) {
                    c.performShowLocked();
                    // It hadn't been shown, which means layout not performed on it, so now we want to make sure to do a layout.  If called from within the transaction loop, this will cause it to restart with a new layout.
                    if (displayContent != null) {
                        displayContent.setLayoutNeeded();
                    }
                }
            }
        }

        return true;
    }

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值