-
-
Save bjoernQ/6975256 to your computer and use it in GitHub Desktop.
<?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(); | |
} | |
} |
There are ways you can "cheat" the android OS, set the targetSdkVersion to 15, then it won't ask you for permission on marshmallow
I have a bug in Genymotion. The MM shield tablet that works.
Need add permiss android.permission.SYSTEM_ALERT_WINDOW in system.
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.
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?
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
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 )
Can I capture screenshot by click on this overlay button? if yes then can you help me how ?
Hey ,
I try that code but the issue is overlaybutton not show anywhere in the screen please anyone guide me
Hi,
The same, I have nothing...
Me too, only see the overlayButton on 4.4 device. I have checked permission on 7.0 but don't see anything
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
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);
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 :(
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
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
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);
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).
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
crashes on Pie with permission denied
Thanks.
thanks
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?
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
.
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?
For "permission denied for window type 2003
at". Please look at my comment and come back.
Thanks, that solved the first error, though I now get 'permission denied for window type 2038' instead
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?
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);
}
Yes , In Jelly Ben 4.2.2 . It worked out, But in Marshmallow, It crashes the APP.