Android6.0 solution to open floating window | permission denied for window type 2003 , 2038

        Android6.0 realizes the function of a floating window, and there are two solutions:

        One is that if you are doing system application development, as long as you sign the apk, then the floating window permission is given by default, which obviously does not meet the requirements of most developers;

        The second is to guide the user to open the permission before opening the floating window: the UI path for permission opening is "General - Application Management - More - Configuration Application - Display on top of other applications - select your APP -- Run on top of other applications to display";

        You need to apply for permissions to make system floating windows, and you need to apply for dynamic permissions if you are above 6.0. The following is the application for dynamic permissions:

[Step 1] Add the permission of the floating window in AndroidManifest.xml

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

[Step 2] Permission application for the floating window

public static int OVERLAY_PERMISSION_REQ_CODE = 1234;

private void checkAndRequestPermissions() {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M 
                        && !Settings.canDrawOverlays(this)){
            Intent intent = 
                 new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                            Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent,OVERLAY_PERMISSION_REQ_CODE);
        }else {
            //todo 正常逻辑
        }
    }

@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onActivityResult(int requestCode, int resultCode, @org.jetbrains.annotations.Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == OVERLAY_PERMISSION_REQ_CODE){
            if(!Settings.canDrawOverlays(this)){
                ToastUtil.showShort("权限授予失败,无法开启悬浮窗");
            }else {
                ToastUtil.showShort("权限授予成功,开启悬浮窗");
                //todo正常逻辑
            }
        }
    }

 The method checkAndRequestPermissions() can guide the user to start the floating window permission;

However, after applying for the permission, it still doesn’t work, and there will be a “permission denied for window type 2003” permission rejection prompt when running. This mainly occurs in this type of setting. The above code is wrong, that is, TYPE_SYSTEM_ALERT because This is abandoned and deprecated. When you go in, you can see that TYPE_APPLICATION_OVERLAY is used; so we need to use different codes according to different versions:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){//6.0
    wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}else {
    wmParams.type =  WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
}

 code show as below:

    private void createFloatView() {
        wmParams = new WindowManager.LayoutParams();
        //获取WindowManagerImpl.CompatModeWrapper
        mWindowManager = (WindowManager) getApplication().getSystemService(getApplication().WINDOW_SERVICE);
        //设置window type
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){//6.0+
            wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        }else {
            wmParams.type =  WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        }
//        wmParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        //设置图片格式,效果为背景透明
        wmParams.format = PixelFormat.RGBA_8888;
        //设置浮动窗口不可聚焦(实现操作除浮动窗口外的其他可见窗口的操作)
        wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;

        //调整悬浮窗显示的停靠位置为左侧置顶
        wmParams.gravity = Gravity.LEFT | Gravity.TOP;

        // 以屏幕左上角为原点,设置x、y初始值
        wmParams.x = 1180;
        wmParams.y = ViewUtil.oriPxToTarPx(200);

        //设置悬浮窗口长宽数据
        wmParams.width = ViewUtil.oriPxToTarPx(100);
        wmParams.height = ViewUtil.oriPxToTarPx(100);

        LayoutInflater inflater = LayoutInflater.from(getApplication());
        //获取浮动窗口视图所在布局
        
        mFloatLayout = (FrameLayout) inflater.inflate(R.layout.service_suspend, null);
        mFloatLayout.setElevation(10F);
        //添加mFloatLayout
        mWindowManager.addView(mFloatLayout, wmParams);

        //浮动窗口按钮
        mFloatView = (ImageView) mFloatLayout.findViewById(R.id.image_suspend_service);
       
        mFloatLayout.measure(View.MeasureSpec.makeMeasureSpec(0,
                View.MeasureSpec.UNSPECIFIED), View.MeasureSpec
                .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
        //设置监听浮动窗口的触摸移动
        mFloatView.setOnTouchListener(new View.OnTouchListener() {
            int x = 0;
            int y = 0;
            private boolean isMoving = false;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();
                int newX = (int) event.getRawX() - mFloatView.getMeasuredWidth() / 2;
                int newY = (int) event.getRawY() - mFloatView.getMeasuredHeight() / 2;

                switch (action) {
                    case MotionEvent.ACTION_DOWN:
                        isMoving = false;
                        x = (int) event.getRawX() - mFloatView.getMeasuredWidth() / 2;
                        y = (int) event.getRawY() - mFloatView.getMeasuredHeight() / 2 - getStatusBarHeight();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        if (Math.sqrt((double) (newX - x) * (double) (newX - x) + (double) (newY - y) * (double) (newY - y)) > ViewUtil.oriPxToTarPx(36) || isMoving) {
                            isMoving = true;
                            wmParams.x = newX;
                            wmParams.y = newY;
                            mWindowManager.updateViewLayout(mFloatLayout, wmParams);
                        }
                        break;
                    case MotionEvent.ACTION_UP:
                        if (Math.sqrt((double) (newX - x) * (double) (newX - x) + (double) (newY - y) * (double) (newY - y)) <= ViewUtil.oriPxToTarPx(36)) {
                            isMoving = false;
                            //逻辑处理
                        }
                        break;
                    default:
                        break;
                }
                return true;
            }
        });
    }

 add:

The device used at that time was 9.0, no problem, it can run, after development, 7.0, terminals below 6.0 will crash, and will report an exception permission denied for window type 2038. After many experiments, I found this permission

wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;

Only versions above Android version 7.1 can be effective, so you can modify the judgment:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1){//7.1+
            wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        }else {
            wmParams.type =  WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        }

The above only modified the judgment of one version, and then it can continue to run;

The above is for reference only;

Guess you like

Origin blog.csdn.net/gqg_guan/article/details/123237918