I'm working on an app where I need to display a window with some info ON the Lock Screen (KeyGuard) without unlocking the phone. I figured I could probably do it with WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
But every time my app crashes with the following error:
android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@40ec8528 -- permission denied for this window type
These posts (here, here and here) all give the same answer. To add the following permission in the Manifest file.
android.permission.SYSTEM_ALERT_WINDOW
Solution that I have implemented but I am still getting the same error. Any idea of what I'm doing wrong?
Here are the permissions in my manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.droidpilot.keyguardwindow" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
And this is the code I use to add the Window to the lock screen
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
LayoutInflater mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mView = mInflater.inflate(R.layout.lock_screen_notif, null);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
PixelFormat.TRANSLUCENT
);
wm.addView(mView, params);
Anybody got any idea?
P.S. I'm testing on an HTC Desire 620 DS running Android 4.4.2
if you use apiLevel >= 19
, don't use
WindowManager.LayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
which gets the following error:
android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@40ec8528 -- permission denied for this window type
Use this instead:
LayoutParams.TYPE_TOAST or TYPE_APPLICATION_PANEL
I guess you should differentiate the target (before and after Oreo)
int LAYOUT_FLAG;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
LAYOUT_FLAG,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
I tried my best to try all the examples available for this issue. Finally I got the answer for this I don know how much is it reliable but my app is not crashing now.
windowManager = (WindowManager)getSystemService(WINDOW_SERVICE);
//here is all the science of params
final LayoutParams myParams = new LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
LayoutParams.TYPE_SYSTEM_ERROR,
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
PixelFormat.TRANSLUCENT
);
In your manifest file just give the permission
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
Addition to this you can also check for the API level if its >=23 then
if(Build.VERSION.SDK_INT >= 23) {
if (!Settings.canDrawOverlays(Activity.this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 1234);
}
}
else
{
Intent intent = new Intent(Activity.this, Service.class);
startService(intent);
}
I hope it helps someone somewhere. Full example https://anam-android-codes.blogspot.in/?m=1
For what should be completely obvious reasons, ordinary Apps are not allowed to create arbitrary windows on top of the lock screen. What do you think I could do if I created a window on your lockscreen that could perfectly imitate the real lockscreen so you couldn't tell the difference?
The technical reason for your error is the use of the TYPE_KEYGUARD_DIALOG
flag - it requires android.permission.INTERNAL_SYSTEM_WINDOW
which is a signature-level permission. This means that only Apps signed with the same certificate as the creator of the permission can use it.
The creator of android.permission.INTERNAL_SYSTEM_WINDOW
is the Android system itself, so unless your App is part of the OS, you don't stand a chance.
There are well defined and well documented ways of notifying the user of information from the lockscreen. You can create customised notifications which show on the lockscreen and the user can interact with them.
For Android API level of 8.0.0, you should use
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
instead of
LayoutParams.TYPE_TOAST or TYPE_APPLICATION_PANEL
or SYSTEM_ALERT
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With