Android: Unable to add window. Permission denied for this window type

AndroidAndroid Windowmanager

Android Problem Overview


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

Android Solutions


Solution 1 - Android

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

Solution 2 - Android

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);

Solution 3 - Android

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

Solution 4 - Android

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.

Solution 5 - Android

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.

Solution 6 - Android

try this code working perfectly

int layout_parms;
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) 
    
    {  
         layout_parms = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
    
    }
      
     else {
    
            layout_parms = WindowManager.LayoutParams.TYPE_PHONE;
           
    }
    
    yourparams = new WindowManager.LayoutParams(       
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            layout_parms,
            WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
            PixelFormat.TRANSLUCENT);

Solution 7 - Android

Search

> Draw over other apps

in your setting and enable your app. For Android 8 Oreo, try

> Settings > Apps & Notifications > App info > Display over other apps > > Enable

Solution 8 - Android

I just added simple view to WindowManager with the following steps:

  1. Create one layout file to show(dummy_layout in my case)
  2. Add permission in manifest and dynamically.
// 1. Show view
private void showCustomPopupMenu()
{
    windowManager = (WindowManager)getSystemService(WINDOW_SERVICE);
    // LayoutInflater layoutInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    // View view = layoutInflater.inflate(R.layout.dummy_layout, null);
    ViewGroup valetModeWindow = (ViewGroup) View.inflate(this, R.layout.dummy_layout, null);
    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;
    }
    WindowManager.LayoutParams params=new WindowManager.LayoutParams(
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.WRAP_CONTENT,
        LAYOUT_FLAG,
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
        PixelFormat.TRANSLUCENT);
        
    params.gravity= Gravity.CENTER|Gravity.CENTER;
    params.x=0;
    params.y=0;
    windowManager.addView(valetModeWindow, params);
}

// 2. Get permissions by asking
if (!Settings.canDrawOverlays(this)) {
    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
    startActivityForResult(intent, 1234);
}

With this you can add a view to WM.

Tested in Pie.

Solution 9 - Android

Firstly you make sure you have add permission in manifest file.

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

Check if the application has draw over other apps permission or not? This permission is by default available for API<23. But for API > 23 you have to ask for the permission in runtime.

 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, 1);
} 

Use This code:

public class ChatHeadService extends Service {

private WindowManager mWindowManager;
private View mChatHeadView;

WindowManager.LayoutParams params;

public ChatHeadService() {
}

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onCreate() {
    super.onCreate();

    Language language = new Language();
    //Inflate the chat head layout we created
    mChatHeadView = LayoutInflater.from(this).inflate(R.layout.dialog_incoming_call, null);


    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
        params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                        | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
                PixelFormat.TRANSLUCENT);

        params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
        params.x = 0;
        params.y = 100;
        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        mWindowManager.addView(mChatHeadView, params);

    } else {
        params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                        | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
                PixelFormat.TRANSLUCENT);


        params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
        params.x = 0;
        params.y = 100;
        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        mWindowManager.addView(mChatHeadView, params);
    }

    TextView tvTitle=mChatHeadView.findViewById(R.id.tvTitle);
    tvTitle.setText("Incoming Call");

    //Set the close button.
    Button btnReject = (Button) mChatHeadView.findViewById(R.id.btnReject);
    btnReject.setText(language.getText(R.string.reject));
    btnReject.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //close the service and remove the chat head from the window
            stopSelf();
        }
    });

    //Drag and move chat head using user's touch action.
    final Button btnAccept = (Button) mChatHeadView.findViewById(R.id.btnAccept);
    btnAccept.setText(language.getText(R.string.accept));


    LinearLayout linearLayoutMain=mChatHeadView.findViewById(R.id.linearLayoutMain);



    linearLayoutMain.setOnTouchListener(new View.OnTouchListener() {
        private int lastAction;
        private int initialX;
        private int initialY;
        private float initialTouchX;
        private float initialTouchY;

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:

                    //remember the initial position.
                    initialX = params.x;
                    initialY = params.y;

                    //get the touch location
                    initialTouchX = event.getRawX();
                    initialTouchY = event.getRawY();

                    lastAction = event.getAction();
                    return true;
                case MotionEvent.ACTION_UP:
                    //As we implemented on touch listener with ACTION_MOVE,
                    //we have to check if the previous action was ACTION_DOWN
                    //to identify if the user clicked the view or not.
                    if (lastAction == MotionEvent.ACTION_DOWN) {
                        //Open the chat conversation click.
                        Intent intent = new Intent(ChatHeadService.this, HomeActivity.class);
                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        startActivity(intent);

                        //close the service and remove the chat heads
                        stopSelf();
                    }
                    lastAction = event.getAction();
                    return true;
                case MotionEvent.ACTION_MOVE:
                    //Calculate the X and Y coordinates of the view.
                    params.x = initialX + (int) (event.getRawX() - initialTouchX);
                    params.y = initialY + (int) (event.getRawY() - initialTouchY);

                    //Update the layout with new X & Y coordinate
                    mWindowManager.updateViewLayout(mChatHeadView, params);
                    lastAction = event.getAction();
                    return true;
            }
            return false;
        }
    });
}

@Override
public void onDestroy() {
    super.onDestroy();
    if (mChatHeadView != null) mWindowManager.removeView(mChatHeadView);
}

}

Solution 10 - Android

change your flag Windowmanger flag "TYPE_SYSTEM_OVERLAY" to "TYPE_APPLICATION_OVERLAY" in your project to make compatible with Android O

WindowManager.LayoutParams.TYPE_PHONE to WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY

Solution 11 - Android

I did manage to finally display a window on the lock screen with the use of TYPE_SYSTEM_OVERLAY instead of TYPE_KEYGUARD_DIALOG. This works as expected and adds the window on the lock screen.

The problem with this is that the window is added on top of everything it possibly can. That is, the window will even appear on top of your keypad/pattern lock in case of secure lock screens. In the case of an unsecured lock screen, it will appear on top of the notification tray if you open it from the lock screen.

For me, that is unacceptable. I hope that this may help anybody else facing this problem.

Solution 12 - Android

LayoutParams.TYPE_PHONE is deprecated. I have updated my code like these.

parameters = if (Build.VERSION.SDK_INT > 25) {
        LayoutParams(
                minHW * 2 / 3, minHW * 2 / 3,
                LayoutParams.TYPE_APPLICATION_OVERLAY,
                LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT)
    }else {
        LayoutParams(
                minHW * 2 / 3, minHW * 2 / 3,
                LayoutParams.TYPE_PHONE,
                LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT)
    }

LayoutParams.TYPE_APPLICATION_OVERLAY requires api level 26 or above.

Solution 13 - Android

The Main Reason for the denying permission is that we don’t have permission for drawing over another apps,We have to provide the permission for the Drawing over other apps that can be done by the following code

Request code for Permission

    public static int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE = 5469;

add this in your MainActivity


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
            askPermission();
}


private void askPermission() {
        Intent intent= new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:"+getPackageName()));
        startActivityForResult(intent,ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
}

Add this also

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(resultCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE){
            if(!Settings.canDrawOverlays(this)){
                askPermission();
            }
        }
    }

Solution 14 - Android

I struggled to find the working solution with ApplicationContext and TYPE_SYSTEM_ALERT and found confusing solutions, In case you want the dialog should be opened from any activity even the dialog is a singleton you have to use getApplicationContext(), and if want the dialog should be TYPE_SYSTEM_ALERT you will need the following steps:

first get the instance of dialog with correct theme, also you need to manage the version compatibility as I did in my following snippet:

AlertDialog.Builder builder = new AlertDialog.Builder(getApplicationContext(), R.style.Theme_AppCompat_Light);

After setting the title, message and buttons you have to build the dialog as:

AlertDialog alert = builder.create();

Now the type plays the main roll here, since this is the reason of crash, I handled the compatibility as following:

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        alert.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY - 1);

    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        alert.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
    }

Note: if you are using a custom dialog with AppCompatDialog as below:

AppCompatDialog dialog = new AppCompatDialog(getApplicationContext(), R.style.Theme_AppCompat_Light);

you can directly define your type to the AppCompatDialog instance as following:

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY - 1);

    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
    }

Don't forget to add the manifest permission:

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

Solution 15 - Android

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
    WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_PHONE,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
            PixelFormat.TRANSLUCENT);

    params.gravity = Gravity.START | Gravity.TOP;
    params.x = left;
    params.y = top;
    windowManager.addView(view, params);

} else {
    WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
            PixelFormat.TRANSLUCENT);


    params.gravity = Gravity.START | Gravity.TOP;
    params.x = left;
    params.y = top;
    windowManager.addView(view, params);
}

Solution 16 - Android

Make sure WindowManager.LayoutParams.TYPE_SYSTEM_ERROR is added for OS version < Oreo as it's been deprecated.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDroidPilotView Question on Stackoverflow
Solution 1 - Androidrecotone2000View Answer on Stackoverflow
Solution 2 - AndroidCédric DufouilView Answer on Stackoverflow
Solution 3 - AndroidAnam AnsariView Answer on Stackoverflow
Solution 4 - AndroidadelphusView Answer on Stackoverflow
Solution 5 - AndroidMingquan LiuView Answer on Stackoverflow
Solution 6 - Androidshakirullah orakzaiView Answer on Stackoverflow
Solution 7 - AndroidJeffNhanView Answer on Stackoverflow
Solution 8 - AndroidRKBView Answer on Stackoverflow
Solution 9 - AndroidAbhijeet SharmaView Answer on Stackoverflow
Solution 10 - AndroidRakesh Kumar B BadigerView Answer on Stackoverflow
Solution 11 - AndroidDroidPilotView Answer on Stackoverflow
Solution 12 - AndroidAshiqul IslamView Answer on Stackoverflow
Solution 13 - Androidsai Pavan KumarView Answer on Stackoverflow
Solution 14 - AndroidHAXMView Answer on Stackoverflow
Solution 15 - AndroidHarpreetView Answer on Stackoverflow
Solution 16 - AndroidJoseView Answer on Stackoverflow