Implementation Principle and Code Example of Android Floating Window

  • 2021-12-05 07:10:36
  • OfStack

1. The realization principle of floating window

See the small Android icon above. It will not be blocked by other components, and it can also respond to user clicks and drag events. Its display and disappearance are directly managed by WindowManager, which is the Android floating window. The implementation of Android floating window mainly depends on WindowManager class. Through addView (), updateViewLayout () and removeView () of WindowManager class, we can directly add, update and remove View from Window.

2. The concrete steps to implement the floating window

1) Since the implementation of floating windows depends on WindowManager, there is no doubt that we have to get the WindowManger object first. Considering that floating windows are usually displayed after the application exits, we need to add and update floating windows in Service, and of course don't forget to provide users with a function to cancel floating windows.

2) Define the View you want to display. You can define it in the layout file, or you can customize the view.

3) Set the necessary parameters, there are several more important parameters need to be set, please refer to the following code.

4) Add View to Window, receive and process events, and update View.

5) Add corresponding permissions to Manifest. < uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/ >

3. Floating window implementation code


 package com.spreadst.floatwindow;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.PixelFormat;
 import android.os.IBinder;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowManager;

 public class FloatWindowService extends Service {

  private static final TAG = "FloatWindowService";

  private WindowManager mWindowManager;
  private WindowManager.LayoutParams mLayoutParams;
  private LayoutInflater mLayoutInflater;
  private View mFloatView;
  private int mCurrentX;
  private int mCurrentY;
  private static int mFloatViewWidth = 50;
  private static int mFloatViewHeight = 80;
  @Override
  public void onCreate() {
    // TODO Auto-generated method stub
    super.onCreate();
    // Initialization WindowManager Object and LayoutInflater Object 
    mWindowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
    mLayoutInflater = LayoutInflater.from(this);
  }
  @Override
  public void onStart(Intent intent, int startId) {
    // TODO Auto-generated method stub
    super.onStart(intent, startId);
    Log.i(TAG, "onStart()");
    createView();
  }
  private void createView() {
    // TODO Auto-generated method stub
    // Load the layout file 
    mFloatView = mLayoutInflater.inflate(R.layout.main, null);
    // For View Set up listening to handle user clicks and drags 
    mFloatView.setOnTouchListener(new OnFloatViewTouchListener());
    /* For View Setting parameters */
    mLayoutParams = new WindowManager.LayoutParams();
    // Settings View Default placement position 
    mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
    // Settings window type
    mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
    // Set the background to transparent 
    mLayoutParams.format = PixelFormat.RGBA_8888;
    // It is important to note that the setting of this property, FLAG_NOT_FOCUSABLE Make the floating window not get focus , If this property is not set, other clicks on the screen are invalid because they cannot get focus 
    mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
    // Set the display position of the view by WindowManager Updating the location of the view is actually changing (x,y) Value of 
    mCurrentX = mLayoutParams.x = 50;
    mCurrentY = mLayoutParams.y = 50;
    // Set the width and height of the view 
    mLayoutParams.width = 100;
    mLayoutParams.height = 100;
    // Add a view to the Window Medium 
    mWindowManager.addView(mFloatView, mLayoutParams);
  }
  /* Due to direct startService(), Therefore, this method is useless */
  @Override
  public IBinder onBind(Intent intent) {
    // TODO Auto-generated method stub
    return null;
  }
  /* This method is used to update the position of the view, which is actually to change the (LayoutParams.x,LayoutParams.y) Value of */
  private void updateFloatView() {
    mLayoutParams.x = mCurrentX;
    mLayoutParams.y = mCurrentY;
    mWindowManager.updateViewLayout(mFloatView, mLayoutParams);
  }
  /* Handle the dragging of the view, here only for the Move Event, the user can also handle the click event, for example, when clicking the floating window, start the main of the application Activity*/
  private class OnFloatViewTouchListener implements View.OnTouchListener {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
      // TODO Auto-generated method stub
      Log.i(TAG, "mCurrentX: " + mCurrentX + ",mCurrentY: "
          + mCurrentY + ",mFloatViewWidth: " + mFloatViewWidth
          + ",mFloatViewHeight: " + mFloatViewHeight);
      /*
       * getRawX(),getRawY() These two methods are very important. Usually, we use the getX(),getY() To get the trigger point coordinates of the event, 
       *  But getX(),getY() What is obtained is the coordinates of the event trigger point relative to the upper left corner of the view; And getRawX(),getRawY() What you get is the event trigger point 
       *  The coordinates relative to the upper left corner of the screen. Due to LayoutParams In x,y Is relative to the screen, so you need to use getRawX(),getRawY() . 
       */
      mCurrentX = (int) event.getRawX() - mFloatViewWidth;
      mCurrentY = (int) event.getRawY() - mFloatViewHeight;
      int action = event.getAction();
      switch (action) {
      case MotionEvent.ACTION_DOWN:
        break;
      case MotionEvent.ACTION_MOVE:
        updateFloatView();
        break;
      case MotionEvent.ACTION_UP:
        break;
      }
      return true;
    }
  }
 }

4. How to display floating windows only in the Launcher interface

Everyone should be familiar with the floating window of 360 Security Guard. Its floating window will only be displayed in Launcher interface. When the user cuts to other interfaces, the floating window will be automatically removed.

To realize this function, we must know the current interface. If we only listen to category of Activity, we can only know when we entered Launcher interface, but we can't know whether we left Launcher interface. So how does 360 realize this function? You can decompile its code under 1. Here is a feasible method. Our current one is actually very simple, that is, to know whether the current Activity is Activity with Launcher interface. Since the Activity is managed as a stack, we just need to see if the Activity at the top of the stack is the Activity of the Launcher. To obtain Task information of Activity, you need to add corresponding permissions in Manifest. < uses-permission android: name = "android.permission.GET_TASKS"/ > .


private String getTopActivity(Context context) {
   // Get ActivityManager Object 
   ActivityManager manager = (ActivityManager)getSystemService(ACTIVITY_SERVICE) ;
   /*
   *  Get the currently running Task List, arranged in chronological order of most recent use, with parameters representing the maximum number of list items to be returned. 
   *  Here we just need to get in onResume State of Activity In Task . 
   */
   List<RunningTaskInfo> runningTaskInfos = manager.getRunningTasks(1) ;
   if(runningTaskInfos != null) {
     // Get the task The top of the stack in Activity
     return (runningTaskInfos.get(0).topActivity).toString() ;
   } else {
     return null;
   }
 }

Related articles: