javaandroidandroid-activityoverlayandroid-view

How to create an 'Always on top overlay' in Android


I'd started an Android project, and I need to create a small image button that is always on top of all applications. I have seen some other apps doing that, and I want it to be like those. It should be movable in the screen (for example, like YouTube or Telegram's video overlays) and should be destroyable too.

I also would like to handle the clicks on my image overlay.

So far I've followed some other tutorials and I have granted the Settings.ACTION_MANAGE_OVERLAY_PERMISSION permission. But I don't know what to do after that.

Any helps would be greatly appreciated


Solution

  • Alright. Heres a piece of code which does the job: (You can change the ImageView to any other thing and use it as an overlay.)

    startPowerOverlay() function:

    @SuppressLint("ClickableViewAccessibility")
        private void startPowerOverlay(){
            // Starts the button overlay.
            windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
            overlayPowerBtn = new ImageView(this);
            overlayPowerBtn.setImageResource(R.drawable.REPLACE_ME);
    
            int LAYOUT_FLAG;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                // APPLICATION_OVERLAY FOR ANDROID 26+ AS THE PREVIOUS VERSION RAISES ERRORS
                LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
            } else {
                // FOR PREVIOUS VERSIONS USE TYPE_PHONE AS THE NEW VERSION IS NOT SUPPORTED
                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,
                    PixelFormat.TRANSLUCENT);
    
            params.gravity = Gravity.TOP | Gravity.START;
            params.x = 0;
            params.y = 100;
            params.height = 110;
            params.width = 110;
    
            windowManager.addView(overlayPowerBtn, params);
    
            overlayPowerBtn.setOnTouchListener(new View.OnTouchListener() {
                private int initialX;
                private int initialY;
                private float initialTouchX;
                private float initialTouchY;
                private long latestPressTime = 0;
    
                @Override public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            // Save current x/y
                            initialX = params.x;
                            initialY = params.y;
                            initialTouchX = event.getRawX();
                            initialTouchY = event.getRawY();
                            // Check for double clicks. 
                            if (latestPressTime == 0 || latestPressTime + 500 < System.currentTimeMillis()) {
                                latestPressTime = System.currentTimeMillis();
                            } else {
                                // Doubleclicked. Do any action you'd like
                            }
                            return true;
                        case MotionEvent.ACTION_UP:
                            return true;
                        case MotionEvent.ACTION_MOVE:
                            params.x = initialX + (int) (event.getRawX() - initialTouchX);
                            params.y = initialY + (int) (event.getRawY() - initialTouchY);
                            windowManager.updateViewLayout(overlayPowerBtn, params);
                            return true;
                    }
                    return false;
                }
            });
        }
    

    on onCreate():

            // Check for overlay permission. If not enabled, request for it. If enabled, show the overlay
            if(Build.VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(context)){
                CharSequence text = "Please grant the access to the application.";
                int duration = Toast.LENGTH_SHORT;
                Toast toast = Toast.makeText(context, text, duration);
                toast.show();
                startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.fromParts("package", getPackageName(), null)));
            } else {
                startPowerOverlay();
            }
    

    on onDestroy():

            if (overlayPowerBtn != null)
                windowManager.removeView(overlayPowerBtn);
    

    Hope it helps.