Permission denied for window type 2038

antoniocapizzi95 picture antoniocapizzi95 · Oct 21, 2018 · Viewed 7k times · Source

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?

Answer

TheWanderer picture TheWanderer · Oct 21, 2018

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.