Search code examples
androidandroid-windowmanagerandroid-layoutparams

Permission denied for window type 2038


I'm fixing an android app not developed by me, a few days ago the client asked me to set the targetSdkVersion to 26 (before it was 14), after I did I noticed that the app crashes in some cases, for example crashes when a ProgressDialog is shown. This is the part of the code with this problem:

mProgressDialog.setTitle(getString(R.string.downloading_data));
mProgressDialog.setMessage(mAlertMsg);
Drawable icon = getActivity().getDrawable(android.R.drawable.ic_dialog_info);
icon.setColorFilter(Color.parseColor("#00cbac"), PorterDuff.Mode.SRC_ATOP);
mProgressDialog.setIcon(icon);
mProgressDialog.setIndeterminate(true);
mProgressDialog.setCancelable(false);
mProgressDialog.setButton(getString(R.string.cancel), loadingButtonListener);
mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
mProgressDialog.show();

When the last line is executed, the app crashes and appears this error in Logcat:

android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@b784d3a -- permission denied for window type 2003

This problem occurs when the app is running in devices that have Android 8 and 9. I looked for solutions to similar problems and I found that it would be better to use WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY instead of TYPE_SYSTEM_ALERT, then I modified the second-last line of the code I wrote in this post but it does not change anything, the app crashes the same and in the log This error appears:

android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@b784d3a -- permission denied for window type 2038

In the Manifest I have the permission:

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

I have also enabled all permissions of the app from the device settings. How can I solve this problem?


Solution

  • Android Oreo and above severely limit which overlay types you're allowed to use, as you have seen. Oreo introduces the new TYPE_APPLICATION_OVERLAY constant for apps to use, while deprecating and disallowing the old constants.

    However, TYPE_APPLICATION_OVERLAY doesn't exist in Nougat and below, and so attempting to use it there will cause a SecurityException.

    Replace

    mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
    

    With

    mProgressDialog.getWindow().setType(
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
            else 
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
    

    As for why it's still crashing on Oreo and above with TYPE_APPLICATION_OVERLAY, the SYSTEM_ALERT_WINDOW permission isn't a normal runtime permission, and doesn't show under the "Permissions" section in the app info. The user-facing name for it is "Draw over other apps" (usually), and it's under the general App Info page or under Settings>>Apps>>Special Access.

    You can't grant it programmatically like with runtime permissions, where you have a simple dialog to grant it. Instead, you need to check if the permission is granted, and if it isn't, launch the Settings page to allow the user to grant it: How to programmatically grant the "draw over other apps" permission in android?


    However, I don't really see why a simple progress dialog needs to be a full-blown overlay. In fact, the ProgressDialog has been completely deprecated. You should consider migrating to a simple ProgressBar or, if you want to keep the ProgressDialog, removing the setType() line.