写一个来电话时出现的悬浮窗,一站解决黑马手机卫士来电悬浮窗的高版本安卓系统的适配问题

黑马程序员

1、解决高版本小米、魅族等手机悬浮窗权限报Android permission denied for window type 2002错误。
2、解决黑马程序员教学视频中悬浮窗在高版本安卓手机上不能移动的问题。

/*************************************************************************************************************/

    Android6.0以上使用WindownManager实现悬浮窗会出现 Android permission denied for window type 2002 错误信息,这个是因为在Android6.0以上我们需要去设置页面设置 允许显示在其他应用上层 才可以正常使用悬浮窗。
6.0以上即使我们在清单文件中注册了

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

在有的手机中依然会报错 解决方法如下
首先判断权限不能用 ContextCompat.checkSelfPermission(context, permission)而是用下面的方法:
@RequiresApi(api = Build.VERSION_CODES.M)
    public static boolean canShowAlert(Context context){
        return Settings.canDrawOverlays(context);
    }
    
如果此方法返回false说明没有开启在其他应用上层显示 这时我们需要让用户手动去开启 否则无法使用悬浮窗
Toast.makeText(getApplicationContext(),"请给予悬浮窗权限",Toast.LENGTH_SHORT).show();
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, START_WINDOW);

/*************************************************************************************************************/

解决黑马程序员教学视频中悬浮窗在高版本安卓手机上不能移动的问题
设置params.type 为WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY即可解决不能移动的问题,具体flags的含义可以参考

Android 悬浮窗基本使用

public void showToast() {
        if (PermissionsUtil.canShowAlert(getApplicationContext())) {
            Log.d(TAG, "showToast: --------------------------有权限可以弹窗");

            mToast_view = View.inflate(getApplicationContext(), R.layout.toast_view, null);

            //设置Toast的具体属性值
            final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
            params.height = WindowManager.LayoutParams.WRAP_CONTENT;
            params.width = WindowManager.LayoutParams.WRAP_CONTENT;
            params.format = PixelFormat.TRANSLUCENT;
            params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
            params.setTitle("Toast");
            //如果不设置这个 悬浮窗不会被移动
            params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
//                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
            //得把原点定在左上才能保证坐标正确 应该是默认的原点不是左上角
            params.gravity = Gravity.LEFT + Gravity.TOP;
            //加载Toast的位置信息
            int toast_location_x = SpUtil.getInt(this, SpKey.TOAST_LOCATION_X, 0);
            int toast_location_y = SpUtil.getInt(this, SpKey.TOAST_LOCATION_Y, 0);
            //控件左上角的x坐标
            params.x = toast_location_x;
            //控件左上角的y坐标
            params.y = toast_location_y;
            Log.d(TAG, "showToast: -----------------------------------params.x = " + params.x);
            Log.d(TAG, "showToast: -----------------------------------params.y = " + params.y);          
            mToast_view.setOnTouchListener(new View.OnTouchListener() {
                private int mStartY;
                private int mStartX;
                @SuppressLint("ClickableViewAccessibility")
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()){
                        //当点击时
                        case MotionEvent.ACTION_DOWN:
                            Log.d(TAG, "onTouch: ----------------------------悬浮窗被按下");
                            //记录起始位置
//                        getX是以组件左上角为坐标原点,获取X坐标轴上的值。
//                        getRawX是以屏幕左上角为左脚做预案,获取X坐标轴上的值。
                            mStartX = (int) event.getRawX();
                            mStartY = (int) event.getRawY();
                            break;
                        //当移动时
                        case MotionEvent.ACTION_MOVE:
                            Log.d(TAG, "onTouch: ----------------------------悬浮窗被移动");
                            //记录移动完的位置
                            int endX = (int) event.getRawX();
                            int endY = (int) event.getRawY();

                            //计算差值
                            int disX = endX - mStartX;
                            int disY = endY - mStartY;

                            //容错处理

                            //得到移动完的具体位置
                            params.x = params.x + disX;
                            params.y = params.y + disY;

                            //更新位置
                            mWm.updateViewLayout(mToast_view,params);

                            //重置起始位置 将最后的位置当成起始位置
                            mStartX = endX;
                            mStartY = endY;
                            break;
                        //当抬起时
                        case MotionEvent.ACTION_UP:
                            //保存位置
                            SpUtil.putInt(getApplicationContext(), SpKey.TOAST_LOCATION_X,params.x);
                            SpUtil.putInt(getApplicationContext(), SpKey.TOAST_LOCATION_Y,params.y);
                            break;
                    }
                    //只有触摸事件时返回值是true才能响应触摸事件
                    //既有触摸事件又有点击事件时 返回false 点击事件才能生效   P964
                    return true;
                }
            });

            //给窗体添加这个吐司
            mWm.addView(mToast_view, params);
        }else {
            Toast.makeText(this,"悬浮窗权限已被拒绝",Toast.LENGTH_SHORT).show();
        }
       }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值