android - Creating a system overlay window (always on top)

ID : 10462

viewed : 25

Tags : androidoverlayandroid

Top 5 Answer for android - Creating a system overlay window (always on top)

vote vote

96

This might be a stupid solution. But it works. If you can improve it, please let me know.

OnCreate of your Service: I have used WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH flag. This is the only change in service.

@Override     public void onCreate() {         super.onCreate();         Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();         mView = new HUDView(this);         WindowManager.LayoutParams params = new WindowManager.LayoutParams(                 WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,                 WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,                 PixelFormat.TRANSLUCENT);         params.gravity = Gravity.RIGHT | Gravity.TOP;         params.setTitle("Load Average");         WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);         wm.addView(mView, params);     } 

Now, you will start getting each and every click event. So, you need to rectify in your event handler.

In your ViewGroup touch event

@Override public boolean onTouchEvent(MotionEvent event) {      // ATTENTION: GET THE X,Y OF EVENT FROM THE PARAMETER     // THEN CHECK IF THAT IS INSIDE YOUR DESIRED AREA       Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();     return true; } 

Also you may need to add this permission to your manifest:

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

85

Following @Sam Lu's answer, Indeed Android 4.x blocks certain types from listening to outside touch events, but some types, such as TYPE_SYSTEM_ALERT, still do the job.

Example

    WindowManager.LayoutParams params = new WindowManager.LayoutParams(             WindowManager.LayoutParams.MATCH_PARENT,             WindowManager.LayoutParams.MATCH_PARENT,             WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,             WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE                     | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL                     | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,             PixelFormat.TRANSLUCENT);      WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);     LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);     View myView = inflater.inflate(R.layout.my_view, null);     myView.setOnTouchListener(new OnTouchListener() {        @Override        public boolean onTouch(View v, MotionEvent event) {            Log.d(TAG, "touch me");            return true;        }      });      // Add layout to window manager     wm.addView(myView, params); 

Permissions

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

80

Starting with Android 4.x, Android team fixed a potential security problem by adding a new function adjustWindowParamsLw() in which it will add FLAG_NOT_FOCUSABLE, FLAG_NOT_TOUCHABLE and remove FLAG_WATCH_OUTSIDE_TOUCH flags for TYPE_SYSTEM_OVERLAY windows.

That is, a TYPE_SYSTEM_OVERLAY window won't receive any touch event on ICS platform and, of course, to use TYPE_SYSTEM_OVERLAY is not a workable solution for ICS and future devices.

vote vote

63

I'm one of the developers of the Tooleap SDK. We also provide a way for developers to display always on top windows and buttons, and and we have dealt with a similar situation.

One problem the answers here haven't addressed is that of the Android "Secured Buttons".

Secured buttons have the filterTouchesWhenObscured property which means they can't be interacted with, if placed under a window, even if that window does not receive any touches. Quoting the Android documentation:

Specifies whether to filter touches when the view's window is obscured by another visible window. When set to true, the view will not receive touches whenever a toast, dialog or other window appears above the view's window. Refer to the {@link android.view.View} security documentation for more details.

An example of such a button is the install button when you try to install third party apks. Any app can display such a button if adding to the view layout the following line:

android:filterTouchesWhenObscured="true" 

If you display an always-on-top window over a "Secured Button", so all the secured button parts that are covered by an overlay will not handle any touches, even if that overlay is not clickable. So if you are planing to display such a window, you should provide a way for the user to move it or dismiss it. And if a part of your overlay is transparent, take into account that your user might be confused why is a certain button in the underlying app is not working for him suddenly.

vote vote

51

WORKING ALWAYS ON TOP IMAGE BUTTON

first of all sorry for my english

i edit your codes and make working image button that listens his touch event do not give touch control to his background elements.

also it gives touch listeners to out of other elements

button alingments are bottom and left

you can chage alingments but you need to chages cordinats in touch event in the if element

import android.annotation.SuppressLint;  import android.app.Service; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PixelFormat; import android.os.IBinder; import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.Toast;  public class HepUstte extends Service {     HUDView mView;      @Override     public void onCreate() {         super.onCreate();             Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();          final Bitmap kangoo = BitmapFactory.decodeResource(getResources(),                 R.drawable.logo_l);           WindowManager.LayoutParams params = new WindowManager.LayoutParams(                 kangoo.getWidth(),                  kangoo.getHeight(),                 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE                 |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL                 |WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,                  PixelFormat.TRANSLUCENT);               params.gravity = Gravity.LEFT | Gravity.BOTTOM;         params.setTitle("Load Average");         WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);            mView = new HUDView(this,kangoo);          mView.setOnTouchListener(new OnTouchListener() {               @Override             public boolean onTouch(View arg0, MotionEvent arg1) {                 // TODO Auto-generated method stub                 //Log.e("kordinatlar", arg1.getX()+":"+arg1.getY()+":"+display.getHeight()+":"+kangoo.getHeight());                 if(arg1.getX()<kangoo.getWidth() & arg1.getY()>0)                 {                  Log.d("tıklandı", "touch me");                 }                 return false;             }              });           wm.addView(mView, params);            }        @Override     public IBinder onBind(Intent arg0) {         // TODO Auto-generated method stub         return null;     }  }    @SuppressLint("DrawAllocation") class HUDView extends ViewGroup {       Bitmap kangoo;      public HUDView(Context context,Bitmap kangoo) {         super(context);          this.kangoo=kangoo;        }       protected void onDraw(Canvas canvas) {         //super.onDraw(canvas);           // delete below line if you want transparent back color, but to understand the sizes use back color         canvas.drawColor(Color.BLACK);          canvas.drawBitmap(kangoo,0 , 0, null);            //canvas.drawText("Hello World", 5, 15, mLoadPaint);      }       protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {     }      public boolean onTouchEvent(MotionEvent event) {         //return super.onTouchEvent(event);        // Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();          return true;     } } 

Top 3 video Explaining android - Creating a system overlay window (always on top)

Related QUESTION?