Skip to content

Instantly share code, notes, and snippets.

@bjoernQ
Created October 14, 2013 13:02
Show Gist options
  • Save bjoernQ/6975256 to your computer and use it in GitHub Desktop.
Save bjoernQ/6975256 to your computer and use it in GitHub Desktop.
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();
}
}
@brucekim
Copy link

thanks

@baekseunghyeok
Copy link

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
Copy link

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
Copy link

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
Copy link

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

@D44IN
Copy link

D44IN commented Jan 6, 2021

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

@D44IN
Copy link

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?

@asadkhan9564
Copy link

use this code it will solve your problem
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
wmParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_TOAST);
} else {
wmParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
}

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