Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Creating a System Overlay (Always on Top over all Apps) in Android
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.mobilej.overlay"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="14" />
<application android:label="SystemOverlay" >
<activity
android:name="de.mobilej.overlay.Main"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="de.mobilej.overlay.OverlayShowingService"
android:exported="false" />
</application>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
</manifest>
package de.mobilej.overlay;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class Main extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent svc = new Intent(this, OverlayShowingService.class);
startService(svc);
finish();
}
}
package de.mobilej.overlay;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.Button;
import android.widget.Toast;
public class OverlayShowingService extends Service implements OnTouchListener, OnClickListener {
private View topLeftView;
private Button overlayedButton;
private float offsetX;
private float offsetY;
private int originalXPos;
private int originalYPos;
private boolean moving;
private WindowManager wm;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
overlayedButton = new Button(this);
overlayedButton.setText("Overlay button");
overlayedButton.setOnTouchListener(this);
overlayedButton.setAlpha(0.0f);
overlayedButton.setBackgroundColor(0x55fe4444);
overlayedButton.setOnClickListener(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, PixelFormat.TRANSLUCENT);
params.gravity = Gravity.LEFT | Gravity.TOP;
params.x = 0;
params.y = 0;
wm.addView(overlayedButton, params);
topLeftView = new View(this);
WindowManager.LayoutParams topLeftParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, PixelFormat.TRANSLUCENT);
topLeftParams.gravity = Gravity.LEFT | Gravity.TOP;
topLeftParams.x = 0;
topLeftParams.y = 0;
topLeftParams.width = 0;
topLeftParams.height = 0;
wm.addView(topLeftView, topLeftParams);
}
@Override
public void onDestroy() {
super.onDestroy();
if (overlayedButton != null) {
wm.removeView(overlayedButton);
wm.removeView(topLeftView);
overlayedButton = null;
topLeftView = null;
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
float x = event.getRawX();
float y = event.getRawY();
moving = false;
int[] location = new int[2];
overlayedButton.getLocationOnScreen(location);
originalXPos = location[0];
originalYPos = location[1];
offsetX = originalXPos - x;
offsetY = originalYPos - y;
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
int[] topLeftLocationOnScreen = new int[2];
topLeftView.getLocationOnScreen(topLeftLocationOnScreen);
System.out.println("topLeftY="+topLeftLocationOnScreen[1]);
System.out.println("originalY="+originalYPos);
float x = event.getRawX();
float y = event.getRawY();
WindowManager.LayoutParams params = (LayoutParams) overlayedButton.getLayoutParams();
int newX = (int) (offsetX + x);
int newY = (int) (offsetY + y);
if (Math.abs(newX - originalXPos) < 1 && Math.abs(newY - originalYPos) < 1 && !moving) {
return false;
}
params.x = newX - (topLeftLocationOnScreen[0]);
params.y = newY - (topLeftLocationOnScreen[1]);
wm.updateViewLayout(overlayedButton, params);
moving = true;
} else if (event.getAction() == MotionEvent.ACTION_UP) {
if (moving) {
return true;
}
}
return false;
}
@Override
public void onClick(View v) {
Toast.makeText(this, "Overlay button click event", Toast.LENGTH_SHORT).show();
}
}
@boldijar

This comment has been minimized.

Copy link

@boldijar boldijar commented Jan 23, 2016

This does not work for me, I can't see anything drawing on top.

@eviltak

This comment has been minimized.

Copy link

@eviltak eviltak commented Apr 29, 2016

@BoldijarPaul Are you compiling for Marshmallow (targetSdk: 23)? Then see this SO answer.

@jaypoojara

This comment has been minimized.

Copy link

@jaypoojara jaypoojara commented Apr 29, 2016

@AravSinghal
actualy @BoldijarPaul is right.
code is perfect just remove this line
overlayedButton.setAlpha(0.0f);
and change color to black
overlayedButton.setBackgroundColor(Color.BLACK);
so that you can see the output.
screenshot_2016-04-29-11-28-05-516

@eviltak

This comment has been minimized.

Copy link

@eviltak eviltak commented Apr 30, 2016

@jaypoojara this code did not work for me as is and after commenting the setAlpha line because I am developing and debugging on Marshmallow, which requires all apps to obtain the permission before they can render a system overlay. That's why I added the if (targetSdkVersion == 23) statement in my previous comment 😄

@berk-can

This comment has been minimized.

Copy link

@berk-can berk-can commented May 7, 2016

awesome code 1 year ago I had spent 3 hours to find resources to write code like you shared, but I cant render png with rounded sides can you help me ?

@RedZello

This comment has been minimized.

Copy link

@RedZello RedZello commented Jun 7, 2016

Yes , In Jelly Ben 4.2.2 . It worked out, But in Marshmallow, It crashes the APP.

@gkuti

This comment has been minimized.

Copy link

@gkuti gkuti commented Jun 30, 2016

There are ways you can "cheat" the android OS, set the targetSdkVersion to 15, then it won't ask you for permission on marshmallow

@THEb0nny

This comment has been minimized.

Copy link

@THEb0nny THEb0nny commented Aug 13, 2016

I have a bug in Genymotion. The MM shield tablet that works.

@THEb0nny

This comment has been minimized.

Copy link

@THEb0nny THEb0nny commented Aug 13, 2016

Need add permiss android.permission.SYSTEM_ALERT_WINDOW in system.

@THEb0nny

This comment has been minimized.

Copy link

@THEb0nny THEb0nny commented Aug 14, 2016

Add you code
public static int OVERLAY_PERMISSION_REQ_CODE = 1;

@TargetApi(Build.VERSION_CODES.M)
    public void checkPermissionOverlay() {
        if (!Settings.canDrawOverlays(this)) {
            Toast.makeText(MainActivity.this, "Нужны права на наложение поверх всех приложений", Toast.LENGTH_LONG).show();
            Intent intentSettings = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
            startActivityForResult(intentSettings, OVERLAY_PERMISSION_REQ_CODE);
        }
    }

and use the method checkPermissionOverlay() before starting Intent svc.

@vgrec

This comment has been minimized.

Copy link

@vgrec vgrec commented Sep 16, 2016

Thank you for the gist!
Could you explain what is the purpose of "topLeftView" that is initialized with width/height of zero, and x/y position is set also to zero?

From observation I noticed that when moving the "overlayedButton", the x position of "topLeftView" is always zero, but the y position varies depending of the screen device the code is running on.
Removing the "topLeftView" makes the button to jump a little when starting to move it. So, "topLeftView" definitely is there for a reason. Could you please say in a couple of words what is the reason?

@bruenor41

This comment has been minimized.

Copy link

@bruenor41 bruenor41 commented Mar 7, 2017

Hi people, I tried this code in Android 7 and it crashes on android 7 :(

java.lang.RuntimeException: Unable to create service test.test.chromeostest.OverlayShowingService: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@30bf239 -- permission denied for window type 2003

Please faces someone the same issue? My application targets sdk version 21

@hatamiarash7

This comment has been minimized.

Copy link

@hatamiarash7 hatamiarash7 commented May 6, 2017

i have a problem .... when i move button to corner of screen, i can't touch system's view like Call button in the following image

https://i.stack.imgur.com/pqJlZ.png

how can i disable any touch in button ? ( ignore my view's touch and touch system's view )

@amitbhoraniya

This comment has been minimized.

Copy link

@amitbhoraniya amitbhoraniya commented Jun 14, 2017

Can I capture screenshot by click on this overlay button? if yes then can you help me how ?

@JatinRaghav

This comment has been minimized.

Copy link

@JatinRaghav JatinRaghav commented Jun 16, 2017

Hey ,
I try that code but the issue is overlaybutton not show anywhere in the screen please anyone guide me

@jewom

This comment has been minimized.

Copy link

@jewom jewom commented Jun 16, 2017

Hi,

The same, I have nothing...

@thanhbinh84

This comment has been minimized.

Copy link

@thanhbinh84 thanhbinh84 commented Jun 26, 2017

Me too, only see the overlayButton on 4.4 device. I have checked permission on 7.0 but don't see anything

@StraleXY

This comment has been minimized.

Copy link

@StraleXY StraleXY commented Aug 19, 2017

Hi guys this works great after removing setAlpha(0,0) also I had a small problems since i'm not in java but I manage to do it..
And now I was wondering how to blur background? Any ideas? I tried with flag_blur_behind (or something like that but nothing seams to happened so.. Cheers and thanks for sharing

@WuerfelDev

This comment has been minimized.

Copy link

@WuerfelDev WuerfelDev commented Nov 25, 2017

I have a button on the main activity which i want to use to destroy the screenoverlay. How to archive this?


It is as easy as calling stopService(svc);
@studymadara

This comment has been minimized.

Copy link

@studymadara studymadara commented Dec 15, 2017

it did worked but the actions don't like ontouch and onclick .

SORRY IT DID WORKED !! but movement is not proper like it tends to go downside of the screen :(

@pattagobi

This comment has been minimized.

Copy link

@pattagobi pattagobi commented Feb 9, 2018

hello everyone, with sdk26

did anybody achieve this?

I am trying to do it for a long week but all I am getting is permission denied for window type 2002

can anybody posts sample code please?

thank you

@SEAbdulbasit

This comment has been minimized.

Copy link

@SEAbdulbasit SEAbdulbasit commented Feb 19, 2018

hello..
can you help me sir, i want to override the default incoming call screen in android. i have searched but got no help..
plz if you could help

@elich11

This comment has been minimized.

Copy link

@elich11 elich11 commented Jul 11, 2018

For sdk26 you need to add:
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 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, PixelFormat.TRANSLUCENT);

@bengaskin

This comment has been minimized.

Copy link

@bengaskin bengaskin commented Feb 23, 2019

This is an old thread, but here's my thoughts:
The color/alpha settings as-is worked for me on kitkat, but not on lollipop.
So I updated them similar to another commenter.

Changed to
overlayedButton.setBackgroundColor(Color.BLUE);
overlayedButton.setTextColor(Color.WHITE);
overlayedButton.getBackground().setAlpha(Math.round(0.33f*255));
(white on transparent light blue: 33% transparency).

All the topleft stuff didn't make sense to me at all. So I commented out all the topLeft / topLeftView code and it made very little difference.

I changed:

params.x = newX - (topLeftLocationOnScreen[0]);
params.y = newY - (topLeftLocationOnScreen[1]);

to:

offsetX = originalXPos - x;
offsetY = originalYPos - y;

I'd be glad to hear an explanation of the topLeft code. I suspect that if it is doing something, it could be done a lot more efficiently, and doesn't have to be a view object of it's own. (Or please tell me otherwise).

@REALmyenemy

This comment has been minimized.

Copy link

@REALmyenemy REALmyenemy commented Mar 15, 2019

I get an error on line 52 (OverlayShowingService) when I use it, target device 8.1 oreo, but project SDK 15. "FATAL EXCEPTION".
at de.mobilej.overlay.OverlayShowingService.onCreate(OverlayShowingService.java:52)

The line
wm.addView(overlayedButton, params);
Why is that?

[Edit]
Seems like you have to replace both
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT with LAYOUT_FLAG as elich11 said in order to work.

Thanks everyone

@mgood7123

This comment has been minimized.

Copy link

@mgood7123 mgood7123 commented May 22, 2019

crashes on Pie with permission denied

@JackyBaby615

This comment has been minimized.

Copy link

@JackyBaby615 JackyBaby615 commented Jun 27, 2019

Thanks.

@brucekim

This comment has been minimized.

Copy link

@brucekim brucekim commented Jul 23, 2019

thanks

@baekseunghyeok

This comment has been minimized.

Copy link

@baekseunghyeok baekseunghyeok commented Jan 15, 2020

I want to make a Overlay (Always on Top over all Apps) in Android 6.0. Your code doesn't work in my android studio.
Could you please help make system?

@alexcomo95

This comment has been minimized.

Copy link

@alexcomo95 alexcomo95 commented Dec 28, 2020

If you get "permission denied for window type 2003 at", here is my fix.

WindowManager.LayoutParams.TYPE_SYSTEM_ALERT is deprecated from SDK 26.

In OverlayShowingService, just replace it with WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY.

@D44IN

This comment has been minimized.

Copy link

@D44IN D44IN commented Jan 6, 2021

I get this error

java.lang.RuntimeException: Unable to create service de.mobilej.overlay.OverlayShowingService: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@4929b7e -- permission denied for window type 2003
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3493)
at android.app.ActivityThread.-wrap4(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1776)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6753)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:482)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@4929b7e -- permission denied for window type 2003
at android.view.ViewRootImpl.setView(ViewRootImpl.java:949)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:356)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
at de.mobilej.overlay.OverlayShowingService.onCreate(OverlayShowingService.java:52)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3483)
at android.app.ActivityThread.-wrap4(Unknown Source:0) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1776) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:164) 
at android.app.ActivityThread.main(ActivityThread.java:6753) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:482) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 

Any way to fix this?

@alexcomo95

This comment has been minimized.

Copy link

@alexcomo95 alexcomo95 commented Jan 6, 2021

For "permission denied for window type 2003
at". Please look at my comment and come back.

@D44IN

This comment has been minimized.

Copy link

@D44IN D44IN commented Jan 6, 2021

Thanks, that solved the first error, though I now get 'permission denied for window type 2038' instead

@D44IN

This comment has been minimized.

Copy link

@D44IN D44IN commented Jan 8, 2021

Ok for 'permission denied for window type 2038' you just need to allow drawing over other apps in settings on phone.

I am trying to use this to create an app to hide rounded screen corners by adding a black bar across top and bottom of screen.
At the moment these black bars appear below the status bar and above the navigation bar, as show in the image
(https://user-images.githubusercontent.com/77055803/104008998-3aeb8f00-51a2-11eb-90e6-43fa2704ce0d.jpg)

Anyone know how to make the overlays position to the absolute top and bottom of screen?

Also the overlay gets rotated with any app that goes to landscape mode, as shown here
(https://user-images.githubusercontent.com/77055803/104009159-7a19e000-51a2-11eb-89d7-7b4ad5d22660.jpg)

How can I make it always appear at the top and bottom edges of the screen, regardless of app rotation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment