Android : Draw View on top of other application

Let’s say that you want to write an app that waiting in the background of the device and listening to something that going to happen, in order to pop-up some window offering information or button to perform a specific action.  It can be even something simple like URL namespace that the user just copied into the clipboard and you want to offer him to do something with this URL.

In order to do this, you need to use  WindowManager inside a Service . The WindowManager have the ability to draw a View on top of everything else, with the right LayoutParams, and specifically, the right WindowManager.LayoutParams Flags.

Let’s show how we can do this. First thing you have to use this permission:

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

And your target API need to be 22 or below, or you will have to deal with permission issues.
Now, you don’t have to have any Activity at all, but for this tutorial, we will use very simple MainActivity:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        startService(new Intent(this, OverlayButtonService.class));
        finish();
    }
}

Inside the OverlayButtonService (don’t forget to register your Service in the manifest) we have the interesting code. We will use very simple View that we will define in R.layout.button.xml file:

<?xml version="1.0" encoding="utf-8"?>
<ImageView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:background="@drawable/btn_bg"
    android:src="@android:drawable/ic_input_add"/>

And the OverlayButtonService code is:

public class OverlayButtonService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT);
        layoutParams.gravity = Gravity.TOP | Gravity.START;
        layoutParams.x = 50;
        layoutParams.y = 50;
        @SuppressLint("InflateParams")
        View btn = ((LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE))
                .inflate(R.layout.button, null);
        final WindowManager windowManager = ((WindowManager) getSystemService(WINDOW_SERVICE));
        windowManager.addView(btn, layoutParams);
        btn.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                //here you can do whatever action you want after click
                close(v);
                return false;
            }
        });

    }


    public void close(View view){
        try {
            final WindowManager windowManager = ((WindowManager) getSystemService(WINDOW_SERVICE));
            windowManager.removeView(view);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            stopSelf();
        }
    }

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

What we do is very simple. We define the LayoutParams to draw the Button in the top left corner, and we use FLAG_NOT_FOCUSABLE as we want that the user will be able to keep communicate the screen without we interrupt it.

The output of this code can be something like that:

The orange button is our button and in the moment the user will touch it, the button will disappear.

The full code in this post can be found here:
https://github.com/yshahak/OverlayButton/tree/master

 

Leave a Reply

Your email address will not be published. Required fields are marked *