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?
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.