Open In App

How to Make a Floating Window Application in Android?

Last Updated : 15 Jan, 2021
Improve
Improve
Like Article
Like
Save
Share
Report

Well, on our desktop computers we can easily restore down windows, do something in the background, and maximize the window whenever we want. But we don’t see this feature in android apps that much. Nowadays we can see android is offering Split Screen, but that’s a feature provided by OS, not the app’s individual feature. Let’s make an app that can minimize and maximize itself on just a button click. This feature can help users, in a lot of ways. Suppose you are reading some pdf document with some mathematical calculations and then a minimized calculator over the pdf viewer app will be very helpful. There are a lot of apps that use this feature like Clipboard, MI Calculator, and many more. Here’s a demo of the final app of this article. Note that we are going to implement this project using the Java language. 

Make a Floating Window Application in Android Sample GIF

Step by Step Implementation

Step 1: Create a New Project

To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Java as the programming language.

Step 2: Let’s make the working platform

  • Add new Colors for the App: Go to values -> colors.xml. Any custom color can be added here. We have added these two colors.

XML




<color name="gfgTheme">#FF2F8D46</color>
<color name="gfgThemeTwo">#FF098043</color>


  • Remove the ActionBar: In Android Studio 4.1, go to values -> themes. There are two themes XML file, one for light mode and one for dark mode. In both of the XML, in the style block change the parent attribute to Theme.MaterialComponents.DayNight.NoActionBar.
  • Change primary Theme color for the App: In the same file, the first item block must be about the primary color of the app. Here the newly added colors are added. In the item block add @color/gfgTheme or @color/gfgThemeTwo.

Step 3: Let’s make all the Layouts first

3.a: Start working on the activity_main.xml file

This XML file makes the layout of the Main Activity of the app. The layout is not so complicated. There’s only a Button, TextView, EditText, and another Button one after another inside a ConstraintLayout. Here is the XML code.

XML




<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    tools:context=".MainActivity">
  
    <Button
        android:id="@+id/buttonMinimize"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="MINIMIZE"
        android:textColor="@android:color/white"
        android:textSize="25sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
  
    <TextView
        android:id="@+id/titleText"
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:gravity="center"
        android:text="GEEKS FOR GEEKS"
        android:textColor="@color/gfgTheme"
        android:textSize="30sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/buttonMinimize" />
  
    <EditText
        android:id="@+id/descEditText"
        android:layout_width="match_parent"
        android:layout_height="330dp"
        android:layout_marginTop="10dp"
        android:gravity="start"
        android:hint="Description"
        android:paddingLeft="20dp"
        android:paddingTop="10dp"
        android:paddingRight="20dp"
        android:paddingBottom="10dp"
        android:textColor="@android:color/black"
        android:textSize="22sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/titleText" />
  
    <Button
        android:id="@+id/saveBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="SAVE"
        android:textColor="@android:color/white"
        android:textSize="25sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/descEditText" />
  
</androidx.constraintlayout.widget.ConstraintLayout>


3.b: Start working on the floating_layout.xml file

Go to res -> layout. Right-click on layout -> New -> Layout Resource File. Add the name of the layout (floating_layout for here). This XML file makes the layout of the floating window. It has the same components just as the Main Layout but with slightly different size constraints. Here is the XML code.

XML




<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white">
  
    <Button
        android:id="@+id/buttonMaximize"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_marginTop="20dp"
        android:background="@color/gfgThemeTwo"
        android:text="MAXIMIZE"
        android:textColor="@android:color/white"
        android:textSize="15sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
  
    <TextView
        android:id="@+id/titleText"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:layout_marginTop="10dp"
        android:gravity="center"
        android:text="GEEKS FOR GEEKS"
        android:textColor="@color/gfgThemeTwo"
        android:textSize="18sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/buttonMaximize" />
  
    <EditText
        android:id="@+id/descEditText"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:gravity="start"
        android:hint="Description"
        android:paddingLeft="20dp"
        android:paddingTop="10dp"
        android:paddingRight="20dp"
        android:paddingBottom="10dp"
        android:textColor="@android:color/black"
        android:textSize="16sp"
        app:layout_constraintBottom_toTopOf="@+id/saveBtn"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/titleText" />
  
    <Button
        android:id="@+id/saveBtn"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:layout_marginBottom="10dp"
        android:background="@color/gfgThemeTwo"
        android:text="SAVE"
        android:textColor="@android:color/white"
        android:textSize="12sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
  
</androidx.constraintlayout.widget.ConstraintLayout>


Step 4: Start working on the Java programs

We made 3 classes here. Obviously, the first one is the MainActivity. The second one is FloatingWindowGFG for the floating window service and the last one is a Common class for two common variables. 

4.a: Let’s make the class for the common variables

  • For this first, let’s make a package first-named Common. Right Click on project package path (com.wheic.floatingedittext for here) -> New -> Package.
  • A window will pop up. The intended package name is written(Common for me). A new package will be created.
  • Right-Click on the newly created package -> New -> Java Class. The intended class name is written(Common for here).
  • Two public String variables are created, one is currentDesc and another is savedDesc. Both are initiated with empty Strings.
  • Here is the code for the Common.java class.

Java




package com.wheic.floatingedittext.Common;
  
public class Common {
    // The EditText String will be 
    // stored in this variable
    // when MINIMIZE or MAXIMIZE 
    // button is pressed
    public static String currentDesc = "";
      
    // The EditText String will be 
    // stored in this variable
    // when SAVE button is pressed
    public static String savedDesc = "";
}


4.b: Start working on the MainActivity.java file

  • First, the reference for the component classes is created. Two Buttons, one AlertDialog, and one EditText reference is created.
  • Before going to onCreate(), some other methods are created.
  • isMyServiceRunning(): This method helps to find whether is the floating window service of this app is running. This function is needed when the same app is opened when already the floating window is visible cause then the floating window service is needed to stop. Here is the code with line by line explanation :

Java




private boolean isMyServiceRunning() {
       // The ACTIVITY_SERVICE is needed to retrieve a 
          // ActivityManager for interacting with the global system
       // It has a constant String value "activity".
       ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
         
          // A loop is needed to get Service information that are currently running in the System.
       // So ActivityManager.RunningServiceInfo is used. It helps to retrieve a
       // particular service information, here its this service.
       // getRunningServices() method returns a list of the services that are currently running
       // and MAX_VALUE is 2147483647. So at most this many services can be returned by this method.
       for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
             
             // If this service is found as a running, it will return true or else false.
           if (FloatingWindowGFG.class.getName().equals(service.service.getClassName())) {
               return true;
           }
       }
       return false;
   }


  • requestOverlayDisplayPermission(): The method helps to redirect the application to the Settings to enable ‘Display over other apps‘. Though for that an extra line needs to be added to the AndroidManifest.xml file. For that go to app -> manifests -> AndroidManifest.xml. Add this line before the application block:

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

Java




private void requestOverlayDisplayPermission() {
        // An AlertDialog is created
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
          
          // This dialog can be closed, just by 
          // taping outside the dialog-box
        builder.setCancelable(true);
    
        // The title of the Dialog-box is set
        builder.setTitle("Screen Overlay Permission Needed");
    
        // The message of the Dialog-box is set
        builder.setMessage("Enable 'Display over other apps' from System Settings.");
    
        // The event of the Positive-Button is set
        builder.setPositiveButton("Open Settings", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // The app will redirect to the 'Display over other apps' in Settings.
                // This is an Implicit Intent. This is needed when any Action is needed 
                  // to perform, here it is
                // redirecting to an other app(Settings).
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
                  
                  // This method will start the intent. It takes two parameter, 
                  // one is the Intent and the other is
                // an requestCode Integer. Here it is -1.
                startActivityForResult(intent, RESULT_OK);
            }
        });
        dialog = builder.create();
        // The Dialog will show in the screen
        dialog.show();
    }


  • checkOverlayDisplayPermission(): This method actually checks that if the API level is more than 23 then whether the ‘Display over other apps‘ is enabled in settings. Here is the code of this function:

Java




private boolean checkOverlayDisplayPermission() {
        // Android Version is lesser than Marshmallow 
          // or the API is lesser than 23
        // doesn't need 'Display over other apps' permission enabling.
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
            // If 'Display over other apps' is not enabled it 
              // will return false or else true
            if (!Settings.canDrawOverlays(this)) {
                return false;
            } else {
                return true;
            }
        } else {
            return true;
        }
    }


  • Now here is the complete code for the MainActivity.java file.

Java




package com.wheic.floatingedittext;
  
import android.app.ActivityManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
  
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
  
import com.wheic.floatingedittext.Common.Common;
  
public class MainActivity extends AppCompatActivity {
  
    // The reference variables for the
    // Button, AlertDialog, EditText 
    // classes are created
    private Button minimizeBtn;
    private AlertDialog dialog;
    private EditText descEditArea;
    private Button save;
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
  
        // The Buttons and the EditText are connected with
        // the corresponding component id used in layout file
        minimizeBtn = findViewById(R.id.buttonMinimize);
        descEditArea = findViewById(R.id.descEditText);
        save = findViewById(R.id.saveBtn);
  
        // If the app is started again while the 
        // floating window service is running
        // then the floating window service will stop
        if (isMyServiceRunning()) {
            // onDestroy() method in FloatingWindowGFG
            // class will be called here
            stopService(new Intent(MainActivity.this, FloatingWindowGFG.class));
        }
  
        // currentDesc String will be empty 
        // at first time launch
        // but the text written in floating 
        // window will not gone
        descEditArea.setText(Common.currentDesc);
        descEditArea.setSelection(descEditArea.getText().toString().length());
  
        // The EditText string will be stored in 
        // currentDesc while writing
        descEditArea.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                // Not Necessary
            }
  
            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                Common.currentDesc = descEditArea.getText().toString();
            }
  
            @Override
            public void afterTextChanged(Editable editable) {
                // Not Necessary
            }
        });
  
        // Here the save button is used just to store the 
        // EditText string in saveDesc variable
        save.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Common.savedDesc = descEditArea.getText().toString();
                descEditArea.setCursorVisible(false);
                descEditArea.clearFocus();
                Toast.makeText(MainActivity.this, "Text Saved!!!", Toast.LENGTH_SHORT).show();
            }
        });
  
        // The Main Button that helps to minimize the app
        minimizeBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // First it confirms whether the
                // 'Display over other apps' permission in given
                if (checkOverlayDisplayPermission()) {
                    // FloatingWindowGFG service is started
                    startService(new Intent(MainActivity.this, FloatingWindowGFG.class));
                    // The MainActivity closes here
                    finish();
                } else {
                    // If permission is not given,
                    // it shows the AlertDialog box and
                    // redirects to the Settings
                    requestOverlayDisplayPermission();
                }
            }
        });
    }
  
    private boolean isMyServiceRunning() {
        // The ACTIVITY_SERVICE is needed to retrieve a
        // ActivityManager for interacting with the global system
        // It has a constant String value "activity".
        ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
          
        // A loop is needed to get Service information that 
        // are currently running in the System.
        // So ActivityManager.RunningServiceInfo is used. 
        // It helps to retrieve a
        // particular service information, here its this service.
        // getRunningServices() method returns a list of the 
        // services that are currently running
        // and MAX_VALUE is 2147483647. So at most this many services
        // can be returned by this method.
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            // If this service is found as a running, 
            // it will return true or else false.
            if (FloatingWindowGFG.class.getName().equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }
  
    private void requestOverlayDisplayPermission() {
        // An AlertDialog is created
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
          
        // This dialog can be closed, just by taping
        // anywhere outside the dialog-box
        builder.setCancelable(true);
          
        // The title of the Dialog-box is set
        builder.setTitle("Screen Overlay Permission Needed");
          
        // The message of the Dialog-box is set
        builder.setMessage("Enable 'Display over other apps' from System Settings.");
          
        // The event of the Positive-Button is set
        builder.setPositiveButton("Open Settings", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // The app will redirect to the 'Display over other apps' in Settings.
                // This is an Implicit Intent. This is needed when any Action is needed
                // to perform, here it is
                // redirecting to an other app(Settings).
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
                  
                // This method will start the intent. It takes two parameter, one is the Intent and the other is
                // an requestCode Integer. Here it is -1.
                startActivityForResult(intent, RESULT_OK);
            }
        });
        dialog = builder.create();
        // The Dialog will 
        // show in the screen
        dialog.show();
    }
  
    private boolean checkOverlayDisplayPermission() {
        // Android Version is lesser than Marshmallow or
        // the API is lesser than 23
        // doesn't need 'Display over other apps' permission enabling.
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
            // If 'Display over other apps' is not enabled
            // it will return false or else true
            if (!Settings.canDrawOverlays(this)) {
                return false;
            } else {
                return true;
            }
        } else {
            return true;
        }
    }
}


4.c: Start working on the FloatingWindowGFG.java file

  • Another class is created named FloatingWindowGFG. Go to project package path (com.wheic.floatingedittext for me) -> New -> Java class and then any intended name is given(FloatingWindowGFG for me).
  • This class inherits the Service class.
  • Now as this class is inherited from the Service class, then this class can be used as a service in the Manifest file. So in the AndroidManifest.xml add this line after the activity block and before the application block ends.

<service android:name=”.FloatingWindowGFG”/>

  • Now here is the code for FloatingWindowGFG.java. The comments have been added for a better explanation:

Java




package com.wheic.floatingedittext;
  
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.IBinder;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
  
import androidx.annotation.Nullable;
  
import com.wheic.floatingedittext.Common.Common;
  
public class FloatingWindowGFG extends Service {
  
    // The reference variables for the
    // ViewGroup, WindowManager.LayoutParams, 
    // WindowManager, Button, EditText classes are created
    private ViewGroup floatView;
    private int LAYOUT_TYPE;
    private WindowManager.LayoutParams floatWindowLayoutParam;
    private WindowManager windowManager;
    private Button maximizeBtn;
    private EditText descEditArea;
    private Button saveBtn;
  
    // As FloatingWindowGFG inherits Service class, 
    // it actually overrides the onBind method
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
  
    @Override
    public void onCreate() {
        super.onCreate();
  
        // The screen height and width are calculated, cause
        // the height and width of the floating window is set depending on this
        DisplayMetrics metrics = getApplicationContext().getResources().getDisplayMetrics();
        int width = metrics.widthPixels;
        int height = metrics.heightPixels;
  
        // To obtain a WindowManager of a different Display,
        // we need a Context for that display, so WINDOW_SERVICE is used
        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
  
        // A LayoutInflater instance is created to retrieve the 
        // LayoutInflater for the floating_layout xml
        LayoutInflater inflater = (LayoutInflater) getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE);
          
        // inflate a new view hierarchy from the floating_layout xml
        floatView = (ViewGroup) inflater.inflate(R.layout.floating_layout, null);
  
        // The Buttons and the EditText are connected with
        // the corresponding component id used in floating_layout xml file
        maximizeBtn = floatView.findViewById(R.id.buttonMaximize);
        descEditArea = floatView.findViewById(R.id.descEditText);
        saveBtn = floatView.findViewById(R.id.saveBtn);
  
        // Just like MainActivity, the text written 
        // in Maximized will stay
        descEditArea.setText(Common.currentDesc);
        descEditArea.setSelection(descEditArea.getText().toString().length());
        descEditArea.setCursorVisible(false);
  
        // WindowManager.LayoutParams takes a lot of parameters to set the
        // the parameters of the layout. One of them is Layout_type.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // If API Level is more than 26, we need TYPE_APPLICATION_OVERLAY
            LAYOUT_TYPE = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            // If API Level is lesser than 26, then we can 
            // use TYPE_SYSTEM_ERROR,
            // TYPE_SYSTEM_OVERLAY, TYPE_PHONE, TYPE_PRIORITY_PHONE.
            // But these are all
            // deprecated in API 26 and later. Here TYPE_TOAST works best.
            LAYOUT_TYPE = WindowManager.LayoutParams.TYPE_TOAST;
        }
  
        // Now the Parameter of the floating-window layout is set.
        // 1) The Width of the window will be 55% of the phone width.
        // 2) The Height of the window will be 58% of the phone height.
        // 3) Layout_Type is already set.
        // 4) Next Parameter is Window_Flag. Here FLAG_NOT_FOCUSABLE is used. But
        // problem with this flag is key inputs can't be given to the EditText.
        // This problem is solved later.
        // 5) Next parameter is Layout_Format. System chooses a format that supports 
        // translucency by PixelFormat.TRANSLUCENT
        floatWindowLayoutParam = new WindowManager.LayoutParams(
                (int) (width * (0.55f)),
                (int) (height * (0.58f)),
                LAYOUT_TYPE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT
        );
  
        // The Gravity of the Floating Window is set. 
        // The Window will appear in the center of the screen
        floatWindowLayoutParam.gravity = Gravity.CENTER;
          
        // X and Y value of the window is set
        floatWindowLayoutParam.x = 0;
        floatWindowLayoutParam.y = 0;
  
        // The ViewGroup that inflates the floating_layout.xml is
        // added to the WindowManager with all the parameters
        windowManager.addView(floatView, floatWindowLayoutParam);
  
        // The button that helps to maximize the app
        maximizeBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // stopSelf() method is used to stop the service if
                // it was previously started
                stopSelf();
                  
                // The window is removed from the screen
                windowManager.removeView(floatView);
                  
                // The app will maximize again. So the MainActivity 
                // class will be called again.
                Intent backToHome = new Intent(FloatingWindowGFG.this, MainActivity.class);
                  
                // 1) FLAG_ACTIVITY_NEW_TASK flag helps activity to start a new task on the history stack.
                // If a task is already running like the floating window service, a new activity will not be started.
                // Instead the task will be brought back to the front just like the MainActivity here
                // 2) FLAG_ACTIVITY_CLEAR_TASK can be used in the conjunction with FLAG_ACTIVITY_NEW_TASK. This flag will
                // kill the existing task first and then new activity is started.
                backToHome.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                startActivity(backToHome);
            }
        });
  
        // The EditText string will be stored 
        // in currentDesc while writing
        descEditArea.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                // Not Necessary
            }
  
            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                Common.currentDesc = descEditArea.getText().toString();
            }
  
            @Override
            public void afterTextChanged(Editable editable) {
                // Not Necessary
            }
        });
  
        // Another feature of the floating window is, the window is movable.
        // The window can be moved at any position on the screen.
        floatView.setOnTouchListener(new View.OnTouchListener() {
            final WindowManager.LayoutParams floatWindowLayoutUpdateParam = floatWindowLayoutParam;
            double x;
            double y;
            double px;
            double py;
  
            @Override
            public boolean onTouch(View v, MotionEvent event) {
  
                switch (event.getAction()) {
                    // When the window will be touched, 
                    // the x and y position of that position
                    // will be retrieved
                    case MotionEvent.ACTION_DOWN:
                        x = floatWindowLayoutUpdateParam.x;
                        y = floatWindowLayoutUpdateParam.y;
                          
                        // returns the original raw X 
                        // coordinate of this event
                        px = event.getRawX();
                          
                        // returns the original raw Y 
                        // coordinate of this event
                        py = event.getRawY();
                        break;
                    // When the window will be dragged around, 
                    // it will update the x, y of the Window Layout Parameter
                    case MotionEvent.ACTION_MOVE:
                        floatWindowLayoutUpdateParam.x = (int) ((x + event.getRawX()) - px);
                        floatWindowLayoutUpdateParam.y = (int) ((y + event.getRawY()) - py);
  
                        // updated parameter is applied to the WindowManager
                        windowManager.updateViewLayout(floatView, floatWindowLayoutUpdateParam);
                        break;
                }
                return false;
            }
        });
  
        // Floating Window Layout Flag is set to FLAG_NOT_FOCUSABLE, 
        // so no input is possible to the EditText. But that's a problem.
        // So, the problem is solved here. The Layout Flag is 
        // changed when the EditText is touched.
        descEditArea.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                descEditArea.setCursorVisible(true);
                WindowManager.LayoutParams floatWindowLayoutParamUpdateFlag = floatWindowLayoutParam;
                // Layout Flag is changed to FLAG_NOT_TOUCH_MODAL which 
                // helps to take inputs inside floating window, but
                // while in EditText the back button won't work and 
                // FLAG_LAYOUT_IN_SCREEN flag helps to keep the window
                // always over the keyboard
                floatWindowLayoutParamUpdateFlag.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
                  
                // WindowManager is updated with the Updated Parameters
                windowManager.updateViewLayout(floatView, floatWindowLayoutParamUpdateFlag);
                return false;
            }
        });
  
  
        saveBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // saves the text in savedDesc variable
                Common.savedDesc = descEditArea.getText().toString();
                descEditArea.setCursorVisible(false);
                WindowManager.LayoutParams floatWindowLayoutParamUpdateFlag = floatWindowLayoutParam;
                floatWindowLayoutParamUpdateFlag.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                  
                // The Layout Flag is changed back to FLAG_NOT_FOCUSABLE. and the Layout is updated with new Flag
                windowManager.updateViewLayout(floatView, floatWindowLayoutParamUpdateFlag);
                  
                // INPUT_METHOD_SERVICE with Context is used 
                // to retrieve a InputMethodManager for
                // accessing input methods which is the soft keyboard here
                InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                  
                // The soft keyboard slides back in
                inputMethodManager.hideSoftInputFromWindow(floatView.getApplicationWindowToken(), 0);
                  
                // A Toast is shown when the text is saved
                Toast.makeText(FloatingWindowGFG.this, "Text Saved!!!", Toast.LENGTH_SHORT).show();
            }
        });
    }
  
    // It is called when stopService() 
    // method is called in MainActivity
    @Override
    public void onDestroy() {
        super.onDestroy();
        stopSelf();
        // Window is removed from the screen
        windowManager.removeView(floatView);
    }
}


Output:

Finally, the project is ready. You can check this project in this GitHub link.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads