美文网首页
悬浮窗不同android版本适配

悬浮窗不同android版本适配

作者: 小歪_de4c | 来源:发表于2018-11-30 11:39 被阅读0次

    实现添加悬浮窗的核心源码代码WindowManagerService#addWindow方法中有以下几个关键:
    1.权限检查
    mPolicy.checkAddPermission(attrs, appOp);
    2.悬浮窗参数调整
    mPolicy.adjustWindowParamsLw(win.mAttrs);

    查看不同android版本的源码对比

    结论:
    1. android 4.4(api 19)之前使用TYPE_TOAST 可以显示,但是不能接收触摸事件和按键事件

    mPolicy实际上是PhoneWindowManager。
    对比checkAddPermission()方法变化结论:

    1. android 4.3(api 18) 开始 TYPE_TOAST根本没有做权限检查, 直接break出去了, 最后返回WindowManagerGlobal.ADD_OKAY。这个就是使用TYPE_TOAST不需要权限显示悬浮窗的原因
    //android 4.3_r2.1
        public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp) {
            int type = attrs.type;
    
            outAppOp[0] = AppOpsManager.OP_NONE;
    
            if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
                    || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
                return WindowManagerGlobal.ADD_OKAY;
            }
            String permission = null;
            switch (type) {
                case TYPE_TOAST:
                    // XXX right now the app process has complete control over
                    // this...  should introduce a token to let the system
                    // monitor/control what they are doing.
                    break;
                case TYPE_DREAM:
                case TYPE_INPUT_METHOD:
                case TYPE_WALLPAPER:
                    // The window manager will check these.
                    break;
                case TYPE_PHONE:
                case TYPE_PRIORITY_PHONE:
                case TYPE_SYSTEM_ALERT:
                case TYPE_SYSTEM_ERROR:
                case TYPE_SYSTEM_OVERLAY:
                    permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
                    outAppOp[0] = AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
                    break;
                default:
                    permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
            }
            if (permission != null) {
                if (mContext.checkCallingOrSelfPermission(permission)
                        != PackageManager.PERMISSION_GRANTED) {
                    return WindowManagerGlobal.ADD_PERMISSION_DENIED;
                }
            }
            return WindowManagerGlobal.ADD_OKAY;
        }
    
    //android 4.4_r1
    public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp) {
            int type = attrs.type;
            outAppOp[0] = AppOpsManager.OP_NONE;
    
            if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
                    || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
                return WindowManagerGlobal.ADD_OKAY;
            }
            String permission = null;
            switch (type) {
                case TYPE_TOAST:
                    // XXX right now the app process has complete control over
                    // this...  should introduce a token to let the system
                    // monitor/control what they are doing.
                    break;
                case TYPE_DREAM:
                case TYPE_INPUT_METHOD:
                case TYPE_WALLPAPER:
                case TYPE_PRIVATE_PRESENTATION:
                    // The window manager will check these.
                    break;
                case TYPE_PHONE:
                case TYPE_PRIORITY_PHONE:
                case TYPE_SYSTEM_ALERT:
                case TYPE_SYSTEM_ERROR:
                case TYPE_SYSTEM_OVERLAY:
                    permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
                    outAppOp[0] = AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
                    break;
                default:
                    permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
            }
            if (permission != null) {
                if (mContext.checkCallingOrSelfPermission(permission)
                        != PackageManager.PERMISSION_GRANTED) {
                    return WindowManagerGlobal.ADD_PERMISSION_DENIED;
                }
            }
            return WindowManagerGlobal.ADD_OKAY;
    }
    
    
    

    对比adjustWindowParamsLw()方法变化结论:

    1. android 4.4(api 19) 之前的TYPE_TOAST不能接收触摸事件和按键事件
    //android 4.3_r2.1
        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_r1
        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;
            }
        }
    

    相关文章

      网友评论

          本文标题:悬浮窗不同android版本适配

          本文链接:https://www.haomeiwen.com/subject/dqarnftx.html