Android floating ball source code [long press judgment, multiple click judgment, automatic edge]

To realize the suspended ball, we need to understand

  • Winodw and WindowManager
  • Serivce

Version: Android 10
Android studio version: 2020.3.1
Targetversion: 30 (26 +)
Gradle version during development; com.android.tools.build:gradle:7.0.0
Application permission: ACTION_MANAGE_OVERLAY_PERMISSION

Effect achieved:

  • Short press
  • It can be pressed for a long time (when you just click, the short press click event will not be triggered), and it can be pressed for two times
  • Without clicking for 10 seconds, it will become a suspension ball with 80% transparency and will not block the text behind the suspension ball

Suspended ball Preview: (private chat with me if you want to lose the attention of the picture)

Start implementation

1. Type of use

First of all, it should be clear that Activity cannot complete a floating ball suspended on the desktop. We must use service. It will not be repeated here. Service is very similar to Activity, but the front is mainly used for some background services. In cooperation with WindowManager, we can complete the effect of floating ball (application shutdown, service shutdown).

2. Authority

At least pop-up permission is required. If the floating ball needs to add other functions, add permissions as needed

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

3. Prepare picture resources

Need to pay attention to private chat

4. Write code

1. Get screen parameters

    public void getSizeOfScreen(){
        WindowManager windowManager=(WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
        SCREEN_HEIGHT=windowManager.getDefaultDisplay().getHeight();
        SCREEN_WIDTH=windowManager.getDefaultDisplay().getWidth();
    }

Screen parameters are very important here to prevent the floating ball from being displayed outside the screen

2.initWindowManager

    @RequiresApi(api = Build.VERSION_CODES.O)
    @SuppressLint("ClickableViewAccessibility")
    public void initWindowManager() {
        windowManager = (WindowManager) getApplicationContext()
                .getSystemService(Context.WINDOW_SERVICE);
        //Here is the view to obtain the binding of WindowManager. The following and the following echo, which is equivalent to binding the two together. Only after binding can we use Manger to control the levitation ball
        //   floatView = new View(getApplicationContext());

        params = new WindowManager.LayoutParams();
        // Set Window Type
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        }
        // Set the suspension box to be untouchable
        params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        // The suspended window cannot be touched, does not accept any events, and does not affect the subsequent event response
        params.format = PixelFormat.RGBA_8888;

        // Automatically set the appropriate width and height of the suspension frame
        setSizeOfBall();
        params.gravity = Gravity.LEFT;
        params.x = 200;
        params.y = 000;
    }

The if else statement in the code is very important. In some outdated blogs on the Internet, if there is no such code, the permission type error will be reported
Note: parm represents the position of the suspended ball
If you want to control your own floating ball, you must know the View coordinate system of Android mobile phone screen
3. Code

public void Drag() {

        // Set the Touch monitor of the floating frame
        if (IS_SHOW) {
            floatView.setOnTouchListener(new View.OnTouchListener() {
                //The variable that holds the last position of the hover box
                int lastX, lastY;
                int paramX, paramY;
                int old_dx = 0, old_dy = 0;

                //Idea: when only touching, moving the floating ball will trigger the ontouch listener (if the hand is released, the floating ball will automatically stick to the edge). If it is touched and not stuck to the edge, if it is suspended in the non edge part
                //You can call the screenshot function to open the screenshot
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            lastX = (int) event.getRawX();
                            lastY = (int) event.getRawY();
                            paramX = params.x;
                            paramY = params.y;
                            isMove=true;//Mobile sign
                            setDrawable();
                            downTime=System.currentTimeMillis();
                            Log.i(TAG, "onTouch: ACTION_DOWN");
                            break;
                        case MotionEvent.ACTION_MOVE:
                            int dx = (int) event.getRawX() - lastX;
                            int dy = (int) event.getRawY() - lastY;
                            params.x = paramX + dx;
                            params.y = paramY + dy;
                            //Determine whether it is a long press
                            isLongPress(event,lastX,lastY);
                            windowManager.updateViewLayout(floatView, params);
                            Log.i(TAG, "onTouch:ACTION_MOVE");
                            old_dy = dy;
                            old_dx = dx;
                            IsTransparent=false;
                            handler.removeMessages(flag3);
                            break;
//                            After canceling the click, the current position is obtained, and the horizontal direction becomes 0,
                        case MotionEvent.ACTION_UP:
                            Log.i(TAG, "onTouch: ACTION_CANCEL" );
                            
                           //Here is a simple automatic welt function
                            if (params.x>SCREEN_WIDTH/2){
                                params.x=SCREEN_WIDTH;
                                windowManager.updateViewLayout(floatView,params);
                            }
                            else{
                                params.x=0;
                                windowManager.updateViewLayout(floatView,params);
                            }
                            
                            isOnceLongPress=false;
                            isMove=false;
                            isTwiceLongPress=false;
                            Transparent();//Set the suspended ball picture to 80 transparent
                            break;
                    }
                    v.performClick();
                    return true;
//                    onTouchListener's onTouch method has higher priority than onTouchEvent and will be triggered first
//                    If the onTouch method returns false, onTouchEvent will be triggered. Otherwise, the onTouchEvent method will not be called
//                    The implementation of built-in events such as click events is based on onTouchEvent. If onTouch returns true, these events will not be triggered
//                    The order is: onTouch – > ontouchevent - > onclick
                    //Data address https://blog.csdn.net/DreamingOfDreams/article/details/83592238
                }
            });
            windowManager.addView(floatView, params);

            Log.i(TAG, "Drag: The suspension ball has addView");
        }
    }


A listener is added to the suspension ball to monitor its click and change its position with the click
The Handler is used in the figure to solve a user-defined gesture and two long press events
Here, we will not explain in detail what a Handler is. In short, its function is to send signals in the code, and then the Handler executes the corresponding code after receiving the signal, and has the functions of delaying transmission and canceling transmission.

I used the following functions in the demo

  • Delayed sending: it can solve the event that the transparency of the suspended ball changes 10 seconds after non clicking
  • Cancel sending: if there is a click event within 10 seconds, cancel sending the signal to change the transparency
    Note: the delayed transmission signal will arrive, and the corresponding code will be triggered to cancel the transmission before transmission
    handler.sendEmptyMessageDelayed(flag1,1000);
    @SuppressLint("HandlerLeak")
    public void initHandler(){
        handler=new Handler(){
            @Override
            public void handleMessage(@NonNull Message msg) {
                switch (msg.what){
                    case flag1:
                        isOnceLongPress=true;
                        handler.removeMessages(flag1);//Prevent message overflow from causing this event to occur twice
                        Log.d(TAG, "handleMessage: Long press event 1" );
                        break;
                    case flag2:
                        isTwiceLongPress=true;
                        handler.removeMessages(flag2);
                        Log.d(TAG, "handleMessage: Long press event 2" );
                        break;
                    case flag3:
                        IsTransparent=true;
                        handler.removeMessages(flag3);
                        Log.d(TAG, "handleMessage: Transparent events" );
                        floatView.setBackgroundResource(R.drawable.ic_floatball_transparent80);
                        break;
                }
            }
        };
    }

Set the picture for the floating ball: set the picture if it is transparent, and create it if it is not displayed

    public void setDrawable() {
        if (IsTransparent){
            floatView.setBackgroundResource(R.drawable.ic_float_ball);
            return;
        }
        if (!IS_SHOW) {
            floatView = new View(getApplicationContext());
            floatView.setBackgroundResource(R.drawable.ic_float_ball);
//            floatView.setBackgroundColor(Color.TRANSPARENT);
            IS_SHOW = true;
            Log.d(TAG, "setDrawable: Suspended ball picture has been loaded");
        }
    }

Need demo private chat

Keywords: Java Android

Added by miltonos on Wed, 02 Feb 2022 20:48:06 +0200