294

I'm trying to create an always-op-top button/clickable-image which stays on top of all the windows all the time.

The proof of concept is

I have been successful and have a running service now. The service displays some text on top left corner of screen all the time while user can freely interact with rest of apps in normal manner.

What I'm doing is subclass ViewGroup and add it to root window manager with flag TYPE_SYSTEM_OVERLAY. Now I want to add a button/clickable-image in place of this text which can receive touch events on itself. I tried overriding "onTouchEvent" for the whole ViewGroup but it does not receive any event.

How can I receive events only on certain parts of my always-on-top view group? Kindly suggest.

public class HUD extends Service {
    HUDView mView;

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

    @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.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                0,
//              WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
//                      | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                PixelFormat.TRANSLUCENT);
        params.gravity = Gravity.RIGHT | Gravity.TOP;
        params.setTitle("Load Average");
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(mView, params);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(getBaseContext(),"onDestroy", Toast.LENGTH_LONG).show();
        if(mView != null)
        {
            ((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(mView);
            mView = null;
        }
    }
}

class HUDView extends ViewGroup {
    private Paint mLoadPaint;

    public HUDView(Context context) {
        super(context);
        Toast.makeText(getContext(),"HUDView", Toast.LENGTH_LONG).show();

        mLoadPaint = new Paint();
        mLoadPaint.setAntiAlias(true);
        mLoadPaint.setTextSize(10);
        mLoadPaint.setARGB(255, 255, 0, 0);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawText("Hello World", 5, 15, mLoadPaint);
    }

    @Override
    protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //return super.onTouchEvent(event);
        Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();
        return true;
    }
}
HarshitMadhav
  • 3,687
  • 5
  • 33
  • 43
coreSOLO
  • 3,409
  • 4
  • 18
  • 22
  • 2
    @coreSOLO, I hope you get you're answer, my oddly similar questions didnt get any response. :) +1 – st0le Dec 19 '10 at 06:44
  • 3
    @st0le I promise I'll spend my night and day until I find the solution and share it with you :) – coreSOLO Dec 19 '10 at 08:02
  • 1
    @st0le Ok maybe you and me can dig it out together, give me a link of your question and let me know how much progress you were able to make... – coreSOLO Dec 19 '10 at 09:01
  • its not much :-\ http://stackoverflow.com/questions/3732935/android-floating-clickable-icon-over-screen – st0le Dec 19 '10 at 09:40
  • lets discuss this as a separate answer, see below... – coreSOLO Dec 19 '10 at 10:01
  • 3
    It's surprising that your `onDraw()` is being called. Shouldn't `dispatchDraw()` be overridden instead? See https://groups.google.com/forum/?fromgroups#!topic/android-developers/oLccWfszuUo – faizal Jul 07 '14 at 17:39
  • @coreSOLO I have a similar issue. Can you help me to solve my question here?https://stackoverflow.com/questions/65405516/touch-event-getaction-does-not-work-under-service-class-in-android-studio – Mohsen Ali Dec 28 '20 at 11:25

16 Answers16

158

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" />
Teo Inke
  • 5,513
  • 3
  • 34
  • 36
Sarwar Erfan
  • 17,604
  • 5
  • 41
  • 55
  • AWESOME!!! Thanks a bunch. I'll try this out and let you know, but I know for sure that it works :) Yes I have a couple of possible improvements in mind for my original service which might optimize event handling. I'll let you know soon! Thanks again! – coreSOLO Dec 19 '10 at 14:02
  • can you give some more codes,when i run the code,but get more errors – pengwang Dec 27 '10 at 10:10
  • 1
    @pengwang: what errors are you getting? This code is not independent, you need to place them in your project with appropriate file names under appropriate project. – Sarwar Erfan Dec 28 '10 at 03:34
  • i am sorry,i only do it as a commom demo. can you give a easy demo in your blog or other link,so that i can study it.thank you – pengwang Dec 28 '10 at 03:45
  • 4
    @pengwang: Find simplest implementation here: https://docs.google.com/leaf?id=0B9OlwWEcpDrCNTc1N2Y3NTAtMWJkZi00NzhiLTg4ODgtMDNjZTAxZWIwOTM0&hl=en – Sarwar Erfan Dec 28 '10 at 12:07
  • 6
    the whole code is correct,i find my mistake,i forget the link Sarwar Erfan i think you edit your answer,it can become more wonderful – pengwang Dec 28 '10 at 13:23
  • @pengwang: This is not a complete tutorial. This question only answers the people who came up to the point of displaying overlay (and necessarily setting required permissions) – Sarwar Erfan Dec 28 '10 at 14:41
  • How do you make it so the activity running behind the overlay does not get triggered when pressing the overlay button? For example if the overlay button is on top of a home screen icon we do not want both the overlay and the icon to be triggered. How can we accomplish this? The application Suprer Manager does this, so it must be possible. – Cameron McBride Jan 17 '11 at 18:42
  • 1
    This answer is very helpful, except for one thing. As used in the code, WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, according to the documentation, "will not receive the full up/move/down gesture". In other words, it not possible to detect swipes or anything else other than a ACTION_DOWN. Well I know that it is possible to detect swipes because Wave Launcher uses this similar concept and they are able to detect swipes. Can anyone explain to me how this works? – Brian Jul 17 '11 at 07:07
  • @Brian: I too want am looking to emulate this "swipe" action. I can't really do much with a simple "TOUCH_OUTSIDE" action event. Yes you can implement if you just want button effects, but I want to get all touch data. This has to be possible, I just keep running into dead ends! – While-E Jan 31 '12 at 18:02
  • @While-E (and also Brian): Could you guys send me what you have done so far so that I can give a try for swipe? You could remove any sensitive information from project code, then upload somewhere and give the link. – Sarwar Erfan Jan 31 '12 at 18:19
  • @SarwarErfan how can I read gestures in service. I am unable to read gestures in above code – Umer Farooq Aug 28 '13 at 19:48
  • @SarwarErfan - Did you face any problems with the back button or requesting focus on edit texts? – Karthik Balakrishnan Dec 07 '13 at 16:41
  • I too am looking for a way to swipe. In my case onTouchEvent does not even respond to anything. I figure there must be a way to add a rectangle and detect an onTouchEvent. I've been browsing through the Pie Control source, in case anyone wants to give that a shot it could be useful. https://github.com/ParanoidAndroid/android_frameworks_base/blob/f26f36fe326865c4f85ad1e4ca32649610a490a4/packages/SystemUI/src/com/android/systemui/statusbar/view/PieMenu.java – Loren Kuich Jan 08 '14 at 06:19
  • 7
    @SarwarErfan - I used this its corking perfectly on 2.3 but onTouch event is not geeting invocked on Android 4.0, 1nd 4.1. Please help – Sanjay Singh Mar 02 '14 at 13:57
  • 2
    From Android Oreo 8.0 and after you can not use the following window types: TYPE_PHONE, TYPE_PRIORITY_PHONE, TYPE_SYSTEM_ALERT, TYPE_SYSTEM_OVERLAY, TYPE_SYSTEM_ERROR. You will have to use TYPE_APPLICATION_OVERLAY and it will not be draggable. – Fivos Oct 11 '18 at 09:56
67

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"/>
Teo Inke
  • 5,513
  • 3
  • 34
  • 36
amirlazarovich
  • 906
  • 7
  • 6
  • 5
    Its making my screen hanged .. Any idea – Viswanath Lekshmanan Apr 05 '13 at 16:38
  • Great post. Hopefully this isn't disabled in future releases either. – Cookster Apr 23 '13 at 16:47
  • Animations won't work on it... :( And it's unable to catch clicks on any view in it on 4.2.X. Any suggestions? – Kamran Ahmed Jun 01 '13 at 05:26
  • It works but when I'm using that shortcut (ie System Level Alert), Other dialogs are not being shown. Why ? – Chimu Aug 19 '13 at 09:58
  • @Arju what do you mean? are you trying to remove it? – amirlazarovich Oct 01 '13 at 04:41
  • @KamranAhmed really? they changed that for TYPE_SYSTEM_ALERT as well now? good to know.. – amirlazarovich Oct 01 '13 at 04:58
  • @Chimu That's really weird I didn't have problems with displaying dialogs after using this trick. Care to share your code? By the way, I would only suggest using this trick when my application adds value to the user by drawing outside of its context. Any other use is a waste of permission and prune to errors. – amirlazarovich Oct 01 '13 at 04:59
  • @amirlazarovich No, it's a different case, they sense the outside touch. My problem is that it consumes the touches which are meant for the controls drawn in it... [My Question](http://stackoverflow.com/questions/18488076/type-phone-overlay-view-doesnt-allow-child-gridview-to-capture-onitemclick-even) – Kamran Ahmed Oct 02 '13 at 06:37
  • The method onTouch should return true, since you want the event to be handled as usual by your application. – Teo Inke May 06 '15 at 17:27
  • Update for Marshmallow: Compiling with TargetSdk 23 will make it all fail. There is a screen in the settings, in which there is a list of apps that are allowed to add an overlay. See http://stackoverflow.com/a/32652625/361169 – Meymann Nov 12 '15 at 12:20
  • @amirlazarovich where to write this code `onCreate()` ? or any other place? – HarshitMadhav Mar 29 '17 at 20:29
18

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.

Remy Lebeau
  • 454,445
  • 28
  • 366
  • 620
Sam Lu
  • 3,068
  • 1
  • 24
  • 32
13

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.

Chin
  • 16,446
  • 27
  • 96
  • 148
Danny
  • 586
  • 5
  • 14
  • Can you please answer my question: http://stackoverflow.com/questions/28964771/application-level-floating-views-with-navigation-in-android – Nauman Afzaal Mar 11 '15 at 06:41
  • there is some activity in android 10 that overlay view can't show above them can you please tell the reason or see my question here it will be very helpful https://stackoverflow.com/questions/59598264/screen-overlay-issue-in-android-10 – Mateen Chaudhry Jan 05 '20 at 10:38
12

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;
    }
}
Onur Öztürk
  • 323
  • 1
  • 3
  • 11
7

TYPE_SYSTEM_OVERLAY This constant was deprecated in since API level 26. Use TYPE_APPLICATION_OVERLAY instead. or **for users below and above android 8

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
    LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}
arwTheDev
  • 79
  • 1
  • 4
6

Actually, you can try WindowManager.LayoutParams.TYPE_SYSTEM_ERROR instead of TYPE_SYSTEM_OVERLAY. It may sound like a hack, but it let you display view on top of everything and still get touch events.

Ov3r1oad
  • 897
  • 1
  • 9
  • 24
  • 1
    I tried every thing to make it working, but no success....but adding TYPE_SYSTEM_ERROR done the job....Actually TYPE_SYSTEM_OVERLAY was blocking the touch.....+1. – Robi Kumar Tomar Mar 24 '18 at 13:35
5

Try this. Works fine in ICS. If You want to stop service simply click the notification generated in statusbar.

 public class HUD extends Service
 {
    protected boolean foreground = false;
    protected boolean cancelNotification = false;
    private Notification notification;
    private View myView;
    protected int id = 0;
    private WindowManager wm;
    private WindowManager.LayoutParams params;
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    public void onCreate() {
        super.onCreate();
       // System.exit(0);
        Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_SHORT).show();
        params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
        params.gravity=Gravity.TOP|Gravity.LEFT;
    wm = (WindowManager) getSystemService(WINDOW_SERVICE);
    inflateview();
    foregroundNotification(1);
    //moveToForeground(1,n,true);
    }     
   @Override
    public void onDestroy() {
        super.onDestroy();
        ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(0);
        Toast.makeText(getBaseContext(),"onDestroy", Toast.LENGTH_SHORT).show();
        if(myView != null)
        {
            ((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(myView);
            myView = null;
        }
    }
    protected Notification foregroundNotification(int notificationId) 
   {    
    notification = new Notification(R.drawable.ic_launcher, "my Notification", System.currentTimeMillis());    
        notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT | Notification.FLAG_ONLY_ALERT_ONCE;   
        notification.setLatestEventInfo(this, "my Notification", "my Notification", notificationIntent());          
        ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).notify(id, notification);            
        return notification;
    }
    private PendingIntent notificationIntent() {
        Intent intent = new Intent(this, stopservice.class);    
        PendingIntent pending = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);    
        return pending;
    }
    public void inflateview()
    {
         LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
            myView = inflater.inflate(R.layout.activity_button, null);
            myView.setOnTouchListener(new OnTouchListener() {
               @Override
               public boolean onTouch(View v, MotionEvent event) {
                   Toast.makeText(getBaseContext(),"onToasttt", Toast.LENGTH_SHORT).show();
                   return false;
               }
             });
            // Add layout to window manager
            wm.addView(myView, params); 
    }
}

UPDATE

Sample here

To create an overlay view, when setting up the LayoutParams DON'T set the type to TYPE_SYSTEM_OVERLAY.

Instead set it to TYPE_PHONE.

Use the following flags:

FLAG_NOT_TOUCH_MODAL

FLAG_WATCH_OUTSIDE_TOUCH
Viswanath Lekshmanan
  • 9,155
  • 1
  • 37
  • 60
4

Found a library that does just that: https://github.com/recruit-lifestyle/FloatingView

There's a sample project in the root folder. I ran it and it works as required. The background is clickable - even if it's another app.

enter image description here

AlikElzin-kilaka
  • 30,165
  • 25
  • 168
  • 248
3

Here is some simple solution, All you need is to inflate XML layout just like you do on list adapters, just make XML layout to inflate it. Here is code that all you need.

 public class HUD extends Service {
    View mView;

    LayoutInflater inflate;
    TextView t;
    Button b;

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

        Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();


        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);

        Display display = wm.getDefaultDisplay();  get phone display size
        int width = display.getWidth();  // deprecated - get phone display width
        int height = display.getHeight(); // deprecated - get phone display height 


        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                width, 
                height,
                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.CENTER;
        params.setTitle("Load Average");

        inflate = (LayoutInflater) getBaseContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        mView = inflate.inflate(R.layout.canvas, null);

        b =  (Button) mView.findViewById(R.id.button1);
        t = (TextView) mView.findViewById(R.id.textView1);
        b.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {
            // TODO Auto-generated method stub
            t.setText("yes you click me ");
        }
       });

        wm.addView(mView, params);

        }



    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

}
Kinjal
  • 1,165
  • 3
  • 13
  • 24
user1668168
  • 71
  • 1
  • 6
2

It uses permission "android.permission.SYSTEM_ALERT_WINDOW" full tutorial on this link : http://androidsrc.net/facebook-chat-like-floating-chat-heads/

AmAn yAdAv
  • 31
  • 3
2

This is an old Question but recently Android has a support for Bubbles. Bubbles are soon going to be launched but currently developers can start using them.They are designed to be an alternative to using SYSTEM_ALERT_WINDOW. Apps like (Facebook Messenger and MusiXMatch use the same concept).

Bubbles

Bubbles are created via the Notification API, you send your notification as normal. If you want it to bubble you need to attach some extra data to it. For more information about Bubbles you can go to the official Android Developer Guide on Bubbles.

Xenolion
  • 9,344
  • 6
  • 25
  • 39
1

If anyone still reading this thread and not able to get this working, I'm very sorry to tell you this way to intercept motion event is considered as bug and fix in android >=4.2.

The motion event you intercepted, although has action as ACTION_OUTSIDE, return 0 in getX and getY. This means you can not see all the motion position on screen, nor can you do anything. I know the doc said It will get x and y, but the truth is it WILL NOT. It seems that this is to block key logger.

If anyone do have a workaround, please leave your comment.

ref: Why does ACTION_OUTSIDE return 0 everytime on KitKat 4.4.2?

https://code.google.com/p/android/issues/detail?id=72746

Community
  • 1
  • 1
Nick Jian
  • 427
  • 4
  • 12
1

by using service you can achieve this :

public class PopupService extends Service{

    private static final String TAG = PopupService.class.getSimpleName();
    WindowManager mWindowManager;
    View mView;
    String type ;

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
//        registerOverlayReceiver();
        type = intent.getStringExtra("type");
        Utils.printLog("type = "+type);
        showDialog(intent.getStringExtra("msg"));
        return super.onStartCommand(intent, flags, startId);
    }

    private void showDialog(String aTitle)
    {
        if(type.equals("when screen is off") | type.equals("always"))
        {
            Utils.printLog("type = "+type);
            PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
            WakeLock mWakeLock = pm.newWakeLock((PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "YourServie");
            mWakeLock.acquire();
            mWakeLock.release();
        }

        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        mView = View.inflate(getApplicationContext(), R.layout.dialog_popup_notification_received, null);
        mView.setTag(TAG);

        int top = getApplicationContext().getResources().getDisplayMetrics().heightPixels / 2;

        LinearLayout dialog = (LinearLayout) mView.findViewById(R.id.pop_exit);
//        android.widget.LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) dialog.getLayoutParams();
//        lp.topMargin = top;
//        lp.bottomMargin = top;
//        mView.setLayoutParams(lp);

        final EditText etMassage = (EditText) mView.findViewById(R.id.editTextInPopupMessageReceived);

        ImageButton imageButtonSend = (ImageButton) mView.findViewById(R.id.imageButtonSendInPopupMessageReceived);
//        lp = (LayoutParams) imageButton.getLayoutParams();
//        lp.topMargin = top - 58;
//        imageButton.setLayoutParams(lp);
        imageButtonSend.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Utils.printLog("clicked");
//                mView.setVisibility(View.INVISIBLE);
                if(!etMassage.getText().toString().equals(""))
                {
                    Utils.printLog("sent");
                    etMassage.setText("");
                }
            }
        });

        TextView close = (TextView) mView.findViewById(R.id.TextViewCloseInPopupMessageReceived);
        close.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                hideDialog();   
            }
        });

        TextView view = (TextView) mView.findViewById(R.id.textviewViewInPopupMessageReceived);
        view.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                hideDialog();   
            }
        });

        TextView message = (TextView) mView.findViewById(R.id.TextViewMessageInPopupMessageReceived);
        message.setText(aTitle);

        final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
        WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
//                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON ,
        PixelFormat.RGBA_8888);

        mView.setVisibility(View.VISIBLE);
        mWindowManager.addView(mView, mLayoutParams);
        mWindowManager.updateViewLayout(mView, mLayoutParams);

    }

    private void hideDialog(){
        if(mView != null && mWindowManager != null){
            mWindowManager.removeView(mView);
            mView = null;
        }
    }
}
Akshay Paliwal
  • 3,050
  • 2
  • 35
  • 42
1

@Sarwar Erfan's answer does not work any longer as Android does not allow adding view with WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY to window to be touchable anymore not with even WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH.

I found solution to this problem. You can check it out in following question

When adding view to window with WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, it is not getting touch event

Community
  • 1
  • 1
patilmandar2007
  • 312
  • 2
  • 11
  • Your referred solution also doesn't work in Marshmallow – Ahmad Shahwaiz Nov 03 '16 at 14:55
  • @AhmadShahwaiz Please check link again I have added comment for problem you mentioned there – patilmandar2007 Nov 04 '16 at 14:04
  • Yes, now its working. But not getting the callback response after calling startActivityForResult(intent, OVERLAY_REQ_CODE); in protected void onActivityResult(int requestCode, int resultCode, Intent data) method. – Ahmad Shahwaiz Nov 07 '16 at 12:55
  • @AhmadShahwaiz Changes mentioned in link are to be called using activity where we get callback in onActivityResult method. If you are checking above permission in Service then you might need to add a dummy transparent activity to be started from service, which can ask user for Permission and then in onActivityResult dummy activity you will get result from user. After you will require to notify your service to add view to window or not depending on user response – patilmandar2007 Nov 08 '16 at 11:20
1

Well try my code, atleast it gives you a string as overlay, you can very well replace it with a button or an image. You wont believe this is my first ever android app LOL. Anyways if you are more experienced with android apps than me, please try

  • changing parameters 2 and 3 in "new WindowManager.LayoutParams"
  • try some different event approach
coreSOLO
  • 3,409
  • 4
  • 18
  • 22