WindowManager悬浮窗TYPE_TOAST

WindowManager的addView是定义在接口ViewManager,同时WindowManager也是一个接口,通过Ctrl+H 看一下继承关机,发现是在WindowManagerImpl继承了WindowManager接口并实现addView方法

WindowManagerImpl.addView

 

mGlobal是WindowManagerGlobal的实例,所以调用的的是WindowManagerGlobal.addView()

WindowManager悬浮窗TYPE_TOAST_第1张图片

代码中创建了一个ViewRootImpl实例root,并且调用root.setView传入view

在ViewRootImpl.setView里最关键的代码是

WindowManager悬浮窗TYPE_TOAST_第2张图片

mWindowSession的类型是IWindowSession,mWindow的类型是IWindow.Stub,这句代码就是利用AIDL进行IPC,实际被调用的是Session.addToDisplay:

WindowManager悬浮窗TYPE_TOAST_第3张图片

mServiceWindowManagerService,继续往下看

WindowManager悬浮窗TYPE_TOAST_第4张图片

mPolicy是标记为final的成员变量:

final WindowManagerPolicy mPolicy =PolicyManager.makeNewWindowManager();

继续看PolicyManager.makeNewWindowManager,实际是Policy.makeNewWindowManager()


现在我们知道mPolicy实际上是PhoneWindowManager,那么

intres =mPolicy.checkAddPermission(attrs, appOp);

实际调用的代码是PhoneWindowManager.checkAddPermission()

WindowManager悬浮窗TYPE_TOAST_第5张图片

TYPE_TOAST不检查permission

TYPE_PHONE检查SYSTEM_ALERT_WINDOW权限

 

TYPE_TOAST不需要权限显示悬浮窗的原因已经找到了,接着刚才addWindow方法的分析,继续看下面一句:

 WindowManager悬浮窗TYPE_TOAST_第6张图片

 

还是在PhoneWindowManager里的方法adjustWindowParamsLw()

注意这里我给出了三个版本的实现,一个是2.02.3.7实现的版本,一个是4.0.14.3.1实现的版本,一个是4.4实现的版本:

 

//Android 2.0 - 2.3.7 PhoneWindowManager

  public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {

    switch (attrs.type) {

      case TYPE_SYSTEM_OVERLAY:

      case TYPE_SECURE_SYSTEM_OVERLAY:

      case TYPE_TOAST:

        // These types of windows can't receive input events.

        attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE

            | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;

        break;

    }

  }

//Android 4.0.1 - 4.3.1 PhoneWindowManager

  public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {

    switch (attrs.type) {

      case TYPE_SYSTEM_OVERLAY:

      case TYPE_SECURE_SYSTEM_OVERLAY:

      case TYPE_TOAST:

        // These types of windows can't receive input events.

        attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE

            | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;

        attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;

        break;

    }

  }

//Android 4.4 PhoneWindowManager

  @Override

  public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {

    switch (attrs.type) {

      case TYPE_SYSTEM_OVERLAY:

      case TYPE_SECURE_SYSTEM_OVERLAY:

        // These types of windows can't receive input events.

        attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE

            | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;

        attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;

        break;

    }

  }

 4.0.1以前,当我们使用TYPE_TOAST, Android会偷偷给我们加上FLAG_NOT_FOCUSABLEFLAG_NOT_TOUCHABLE,4.0.1开始,会额外再去掉FLAG_WATCH_OUTSIDE_TOUCH,这样真的是什么事件都没了.4.4开始, TYPE_TOAST被移除了,所以从4.4开始,使用TYPE_TOAST的同时还可以接收触摸事件和按键事件了,4.4以前只能显示出来,不能交互.

API level 18及以下使用TYPE_TOAST无法接收触摸事件的原因也找到了.

API level 18及以下可以使用TYPE_PHONE实现可以接收触摸时间的view

 

 

 

你可能感兴趣的:(Android开发)