Open In App

How to Make a Floating Window Application in Android?

Last Updated : 04 May, 2025
Comments
Improve
Suggest changes
Like Article
Like
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 & Kotlin language. 


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.

Step 2: Add permission in manifest file

Navigate to app > manifests > AndroidManifest.xml and add the following permission

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

Step 3: Create an object class

Navigate to app > java > {package-name}, right click on the folder and select, New > Java/Kotlin Class/File and name it as Common. Create two public String variables, one is currentDesc and another is savedDesc. Both are initiated with empty Strings.

Common.java
package org.geeksforgeeks.demo;

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 = "";
}
Common.kt
package org.geeksforgeeks.demo

object Common {
    // The EditText String will be
    // stored in this variable
    // when MINIMIZE or MAXIMIZE
    // button is pressed
    var currentDesc: String = ""

    // The EditText String will be
    // stored in this variable
    // when SAVE button is pressed
    var savedDesc: String = ""
}


Step 4: Working with layouts

Create a new layout and name it as floating_layout.xml and navigate to activity_main.xml and add the following code in the two files.

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:orientation="vertical"
    android:gravity="center"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/buttonMinimize"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Minimize"
        android:textSize="24sp" />

    <TextView
        android:id="@+id/titleText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="GeeksforGeeks"
        android:textSize="32sp"
        android:textStyle="bold" />

    <EditText
        android:id="@+id/descEditText"
        android:layout_width="match_parent"
        android:layout_height="350dp"
        android:gravity="start"
        android:hint="Description"
        android:padding="16dp"
        android:textColor="@color/black"
        android:textSize="24sp" />

    <Button
        android:id="@+id/saveBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Save"
        android:textColor="@android:color/white"
        android:textSize="24sp" />

</LinearLayout>
floating_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    android:orientation="vertical"
    android:gravity="center">

    <Button
        android:id="@+id/buttonMaximize"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="Maximize" />

    <TextView
        android:id="@+id/titleText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="GeeksforGeeks"
        android:textSize="24sp"
        android:textStyle="bold" />

    <EditText
        android:id="@+id/descEditText"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:gravity="start"
        android:hint="Description"
        android:textColor="@color/black" />

    <Button
        android:id="@+id/saveBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="Save" />

</LinearLayout>


Design UI:

floating-window-android



Step 5: Create a new Service

Create a new Java or Kotlin class file with the name FloatingWindowService and add the following code. 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=”.FloatingWindowService”/>

FloatingWindowService.java
package org.geeksforgeeks.demo;

import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.text.Editable;
import android.text.TextWatcher;
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;

public class FloatingWindowService extends Service {

    // Declare variables for views and WindowManager
    private ViewGroup floatView;
    private WindowManager.LayoutParams floatWindowLayoutParam;
    private WindowManager windowManager;
    private Button maximizeBtn;
    private EditText descEditArea;
    private Button saveBtn;

    // This method is required but not used in this Service
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    // Service is created
    @SuppressLint("ClickableViewAccessibility")
    @Override
    public void onCreate() {
        super.onCreate();

        // Get screen width and height in pixels
        float width = getResources().getDisplayMetrics().widthPixels;
        float height = getResources().getDisplayMetrics().heightPixels;

        // Get the WindowManager system service for handling windows on the screen
        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

        // Inflate the floating window layout using the LayoutInflater system service
        LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
        floatView = (ViewGroup) inflater.inflate(R.layout.floating_layout, null);

        // Initialize the views from the layout file
        maximizeBtn = floatView.findViewById(R.id.buttonMaximize);
        descEditArea = floatView.findViewById(R.id.descEditText);
        saveBtn = floatView.findViewById(R.id.saveBtn);

        // Set the initial text in the EditText and place the cursor at the end
        descEditArea.setText(Common.currentDesc);
        descEditArea.setSelection(descEditArea.getText().length());
        // Hide the cursor initially
        descEditArea.setCursorVisible(false);

        // Set up the parameters for the floating window (size, position, etc.)
        floatWindowLayoutParam = new WindowManager.LayoutParams(
                // Set width to 60% of screen width
                (int) (width * 0.6f),
                // Set height to 50% of screen height
                (int) (height * 0.5f),
                // Type for overlay window
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
                // Make it not focusable
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                // Set transparent background for the window
                PixelFormat.TRANSLUCENT
        );
        floatWindowLayoutParam.gravity = Gravity.CENTER;
        floatWindowLayoutParam.x = 0;
        floatWindowLayoutParam.y = 0;

        // Add the floating view to the window using the WindowManager
        windowManager.addView(floatView, floatWindowLayoutParam);

        // Set up a listener for the maximize button to stop the service and navigate to MainActivity
        maximizeBtn.setOnClickListener(view -> {
            stopSelf();  // Stop the service
            windowManager.removeView(floatView);  // Remove the floating window
            Intent backToHome = new Intent(this, MainActivity.class);
            backToHome.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            startActivity(backToHome);
        });

        // Set up a TextWatcher to update the current description when the text changes
        descEditArea.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {}

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                // Update the current description with the text in the EditText
                Common.currentDesc = descEditArea.getText().toString();
            }

            @Override
            public void afterTextChanged(Editable editable) {}
        });

        // Set up the touch listener for the floating window to allow dragging it around
        setupFloatingWindowMovement();

        // Set up a listener for the EditText to make the cursor visible when clicked
        descEditArea.setOnTouchListener((v, event) -> {
            descEditArea.setCursorVisible(true);  // Make the cursor visible when touched
            floatWindowLayoutParam.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
                    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
            windowManager.updateViewLayout(floatView, floatWindowLayoutParam);  // Update the layout
            return false;
        });

        // Set up a listener for the save button to save the text and hide the soft keyboard
        saveBtn.setOnClickListener(view -> {
            // Save the text in the EditText to the Common object
            Common.savedDesc = descEditArea.getText().toString();
            // Hide the cursor after saving
            descEditArea.setCursorVisible(false);
            // Make the window non-interactive
            floatWindowLayoutParam.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
            windowManager.updateViewLayout(floatView, floatWindowLayoutParam);
            InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(floatView.getWindowToken(), 0);
            Toast.makeText(this, "Text Saved!", Toast.LENGTH_SHORT).show();
        });
    }

    // This method is responsible for handling the movement of the floating window
    @SuppressLint("ClickableViewAccessibility")
    private void setupFloatingWindowMovement() {
        double initialX = 0.0;
        double initialY = 0.0;
        double initialTouchX = 0.0;
        double initialTouchY = 0.0;

        // Set a touch listener to detect dragging
        floatView.setOnTouchListener((view, event) -> {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    // Record the initial position and touch points when the touch starts
                    initialX = floatWindowLayoutParam.x;
                    initialY = floatWindowLayoutParam.y;
                    initialTouchX = event.getRawX();
                    initialTouchY = event.getRawY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    // Calculate the new position of the window based on the movement of the touch
                    floatWindowLayoutParam.x = (int) ((initialX + event.getRawX()) - initialTouchX);
                    floatWindowLayoutParam.y = (int) ((initialY + event.getRawY()) - initialTouchY);
                    // Update the layout
                    windowManager.updateViewLayout(floatView, floatWindowLayoutParam);
                    break;
            }
            return false;
        });
    }

    // This method is called when the service is destroyed
    @Override
    public void onDestroy() {
        super.onDestroy();
        try {
            // Remove the floating window from the screen
            windowManager.removeView(floatView);
        } catch (Exception e) {
            // Handle any potential errors
            e.printStackTrace();
        }
    }
}
FloatingWindowService.kt
package org.geeksforgeeks.demo

import android.annotation.SuppressLint
import android.app.Service
import android.content.Intent
import android.graphics.PixelFormat
import android.os.IBinder
import android.text.Editable
import android.text.TextWatcher
import android.view.*
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.EditText
import android.widget.Toast

class FloatingWindowService : Service() {

    // Declare variables for views and WindowManager
    private lateinit var floatView: ViewGroup
    private lateinit var floatWindowLayoutParam: WindowManager.LayoutParams
    private lateinit var windowManager: WindowManager
    private lateinit var maximizeBtn: Button
    private lateinit var descEditArea: EditText
    private lateinit var saveBtn: Button

    // This method is required but not used in this Service
    override fun onBind(intent: Intent?): IBinder? = null

    // Service is created
    @SuppressLint("ClickableViewAccessibility")
    override fun onCreate() {
        super.onCreate()

        // Get screen width and height in pixels
        val metrics = resources.displayMetrics
        val width = metrics.widthPixels
        val height = metrics.heightPixels

        // Get the WindowManager system service for handling windows on the screen
        windowManager = getSystemService(WINDOW_SERVICE) as WindowManager

        // Inflate the floating window layout using the LayoutInflater system service
        val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
        floatView = inflater.inflate(R.layout.floating_layout, null) as ViewGroup

        // Initialize the views from the layout file
        maximizeBtn = floatView.findViewById(R.id.buttonMaximize)
        descEditArea = floatView.findViewById(R.id.descEditText)
        saveBtn = floatView.findViewById(R.id.saveBtn)

        // Set the initial text in the EditText and place the cursor at the end
        descEditArea.apply {
            setText(Common.currentDesc)
            setSelection(text.length)
            // Hide the cursor initially
            isCursorVisible = false
        }

        // Set up the parameters for the floating window (size, position, etc.)
        floatWindowLayoutParam = WindowManager.LayoutParams(
            // Set width to 60% of screen width
            (width * 0.6f).toInt(),
            // Set height to 50% of screen height
            (height * 0.5f).toInt(),
            // Type for overlay window
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
            // Make it not focusable
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
            // Set transparent background for the window
            PixelFormat.TRANSLUCENT
        ).apply {
            // Position the window at the center of the screen
            gravity = Gravity.CENTER
            x = 0
            y = 0
        }

        // Add the floating view to the window using the WindowManager
        windowManager.addView(floatView, floatWindowLayoutParam)

        // Set up a listener for the maximize button to stop the service and navigate to MainActivity
        maximizeBtn.setOnClickListener {
            stopSelf()  // Stop the service
            windowManager.removeView(floatView)  // Remove the floating window
            val backToHome = Intent(this, MainActivity::class.java).apply {
                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
            }
            startActivity(backToHome)
        }

        // Set up a TextWatcher to update the current description when the text changes
        descEditArea.addTextChangedListener(object : TextWatcher {
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                // Update the current description with the text in the EditText
                Common.currentDesc = descEditArea.text.toString()
            }
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun afterTextChanged(s: Editable?) {}
        })

        // Set up the touch listener for the floating window to allow dragging it around
        setupFloatingWindowMovement()

        // Set up a listener for the EditText to make the cursor visible when clicked
        descEditArea.setOnTouchListener { _, _ ->
            descEditArea.isCursorVisible = true  // Make the cursor visible when touched
            floatWindowLayoutParam.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
                    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
            windowManager.updateViewLayout(floatView, floatWindowLayoutParam)  // Update the layout
            false
        }

        // Set up a listener for the save button to save the text and hide the soft keyboard
        saveBtn.setOnClickListener {
            // Save the text in the EditText to the Common object
            Common.savedDesc = descEditArea.text.toString()
            // Hide the cursor after saving
            descEditArea.isCursorVisible = false
            // Make the window non-interactive
            floatWindowLayoutParam.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE  
            windowManager.updateViewLayout(floatView, floatWindowLayoutParam)
            val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
            inputMethodManager.hideSoftInputFromWindow(floatView.windowToken, 0) 
            Toast.makeText(this, "Text Saved!", Toast.LENGTH_SHORT).show()
        }
    }

    // This method is responsible for handling the movement of the floating window
    @SuppressLint("ClickableViewAccessibility")
    private fun setupFloatingWindowMovement() {
        var initialX = 0.0
        var initialY = 0.0
        var initialTouchX = 0.0
        var initialTouchY = 0.0

        // Set a touch listener to detect dragging
        floatView.setOnTouchListener { _, event ->
            when (event.action) {
                MotionEvent.ACTION_DOWN -> {
                    // Record the initial position and touch points when the touch starts
                    initialX = floatWindowLayoutParam.x.toDouble()
                    initialY = floatWindowLayoutParam.y.toDouble()
                    initialTouchX = event.rawX.toDouble()
                    initialTouchY = event.rawY.toDouble()
                }
                MotionEvent.ACTION_MOVE -> {
                    // Calculate the new position of the window based on the movement of the touch
                    floatWindowLayoutParam.x = ((initialX + event.rawX) - initialTouchX).toInt()
                    floatWindowLayoutParam.y = ((initialY + event.rawY) - initialTouchY).toInt()
                    // Update the layout
                    windowManager.updateViewLayout(floatView, floatWindowLayoutParam) 
                }
            }
            false
        }
    }

    // This method is called when the service is destroyed
    override fun onDestroy() {
        super.onDestroy()
        try {
            // Remove the floating window from the screen
            windowManager.removeView(floatView)  
        } catch (e: Exception) {
            // Handle any potential errors
            e.printStackTrace()  
        }
    }
}


Step 6: Working with MainActivity file

Navigate to the MainActivity file and make the following changes.

MainActivity.java
package org.geeksforgeeks.demo;

import android.app.ActivityManager;
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.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    // Declare the UI components (buttons and edit text)
    private Button minimizeBtn;
    private EditText descEditArea;
    private Button save;

    // Register for result to handle overlay permission
    private final ActivityResultContracts.StartActivityForResult overlayPermissionLauncher =
            registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
                if (checkOverlayDisplayPermission()) {
                    // If permission is granted, start the floating window service
                    startService(new Intent(MainActivity.this, FloatingWindowService.class));
                    finish(); // Close the current activity
                } else {
                    // If permission is not granted, show a toast message
                    Toast.makeText(MainActivity.this, "Permission not granted", Toast.LENGTH_SHORT).show();
                }
            });

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Initialize the UI components
        minimizeBtn = findViewById(R.id.buttonMinimize);
        descEditArea = findViewById(R.id.descEditText);
        save = findViewById(R.id.saveBtn);

        // Check if the floating window service is already running, and stop it if it is
        if (isServiceRunning(FloatingWindowService.class)) {
            stopService(new Intent(this, FloatingWindowService.class));
        }

        // Set the text of the description edit text field from the Common.currentDesc variable
        descEditArea.setText(Common.currentDesc);
        // Move the cursor to the end of the text
        descEditArea.setSelection(descEditArea.getText().length());

        // Add a TextWatcher to update Common.currentDesc whenever the text in the edit area changes
        descEditArea.addTextChangedListener(new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                Common.currentDesc = descEditArea.getText().toString(); // Update the currentDesc variable
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

            @Override
            public void afterTextChanged(Editable s) {}
        });

        // Set an OnClickListener for the save button
        save.setOnClickListener(v -> {
            // Save the text from the edit area to the savedDesc variable
            Common.savedDesc = descEditArea.getText().toString();
            // Remove focus from the edit text field and hide the cursor
            descEditArea.clearFocus();
            descEditArea.setCursorVisible(false);
            // Show a toast message to notify the user that the text has been saved
            Toast.makeText(MainActivity.this, "Text Saved!", Toast.LENGTH_SHORT).show();
        });

        // Set an OnClickListener for the minimize button
        minimizeBtn.setOnClickListener(v -> {
            // Check if overlay permission is granted
            if (checkOverlayDisplayPermission()) {
                // If permission is granted, start the floating window service and finish the activity
                startService(new Intent(MainActivity.this, FloatingWindowService.class));
                finish();
            } else {
                // If permission is not granted, request overlay permission
                requestOverlayDisplayPermission();
            }
        });
    }

    // Check if a service is currently running
    private boolean isServiceRunning(Class<?> serviceClass) {
        ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        // Check if the service is running using the deprecated method (for compatibility)
        @SuppressWarnings("deprecation")
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (service.service.getClassName().equals(serviceClass.getName())) {
                return true;
            }
        }
        return false;
    }

    // Request the user to enable the "Display over other apps" permission from system settings
    private void requestOverlayDisplayPermission() {
        new AlertDialog.Builder(this)
                .setTitle("Screen Overlay Permission Needed") // Title of the dialog
                .setMessage("Enable 'Display over other apps' from System Settings.") // Message in the dialog
                .setCancelable(true) // Allow the dialog to be canceled
                .setPositiveButton("Open Settings", (dialog, which) -> {
                    // If the user clicks "Open Settings", open the system settings for overlay permission
                    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                            Uri.parse("package:" + getPackageName()));
                    overlayPermissionLauncher.launch(intent); // Launch the settings activity
                })
                .show(); // Show the dialog
    }

    // Check if the app has the overlay permission
    private boolean checkOverlayDisplayPermission() {
        // If the SDK version is below Marshmallow (API 23), overlay permission is not needed
        return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(this);
    }
}
MainActivity.kt
package org.geeksforgeeks.demo

import android.app.ActivityManager
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.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    // Declare the UI components (buttons and edit text)
    private lateinit var minimizeBtn: Button
    private lateinit var descEditArea: EditText
    private lateinit var save: Button

    // Register for result to handle overlay permission
    private val overlayPermissionLauncher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) {
        if (checkOverlayDisplayPermission()) {
            // If permission is granted, start the floating window service
            startService(Intent(this, FloatingWindowService::class.java))
            finish() // Close the current activity
        } else {
            // If permission is not granted, show a toast message
            Toast.makeText(this, "Permission not granted", Toast.LENGTH_SHORT).show()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Initialize the UI components
        minimizeBtn = findViewById(R.id.buttonMinimize)
        descEditArea = findViewById(R.id.descEditText)
        save = findViewById(R.id.saveBtn)

        // Check if the floating window service is already running, and stop it if it is
        if (isServiceRunning(FloatingWindowService::class.java)) {
            stopService(Intent(this, FloatingWindowService::class.java))
        }

        // Set the text of the description edit text field from the Common.currentDesc variable
        descEditArea.setText(Common.currentDesc)
        // Move the cursor to the end of the text
        descEditArea.setSelection(descEditArea.text.length)

        // Add a TextWatcher to update Common.currentDesc whenever the text in the edit area changes
        descEditArea.addTextChangedListener(object : TextWatcher {
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                Common.currentDesc = descEditArea.text.toString() // Update the currentDesc variable
            }
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun afterTextChanged(s: Editable?) {}
        })

        // Set an OnClickListener for the save button
        save.setOnClickListener {
            // Save the text from the edit area to the savedDesc variable
            Common.savedDesc = descEditArea.text.toString()
            // Remove focus from the edit text field and hide the cursor
            descEditArea.apply {
                clearFocus()
                isCursorVisible = false
            }
            // Show a toast message to notify the user that the text has been saved
            Toast.makeText(this, "Text Saved!", Toast.LENGTH_SHORT).show()
        }

        // Set an OnClickListener for the minimize button
        minimizeBtn.setOnClickListener {
            // Check if overlay permission is granted
            if (checkOverlayDisplayPermission()) {
                // If permission is granted, start the floating window service and finish the activity
                startService(Intent(this, FloatingWindowService::class.java))
                finish()
            } else {
                // If permission is not granted, request overlay permission
                requestOverlayDisplayPermission()
            }
        }
    }

    // Check if a service is currently running
    private fun isServiceRunning(serviceClass: Class<*>): Boolean {
        val manager = getSystemService(ACTIVITY_SERVICE) as ActivityManager
        @Suppress("DEPRECATION")
        return manager.getRunningServices(Int.MAX_VALUE)
            .any { it.service.className == serviceClass.name }
    }

    // Request the user to enable the "Display over other apps" permission from system settings
    private fun requestOverlayDisplayPermission() {
        AlertDialog.Builder(this)
            .setTitle("Screen Overlay Permission Needed") // Title of the dialog
            .setMessage("Enable 'Display over other apps' from System Settings.") // Message in the dialog
            .setCancelable(true) // Allow the dialog to be canceled
            .setPositiveButton("Open Settings") { _, _ ->
                // If the user clicks "Open Settings", open the system settings for overlay permission
                val intent = Intent(
                    Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:$packageName")
                )
                overlayPermissionLauncher.launch(intent) // Launch the settings activity
            }
            .show() // Show the dialog
    }

    // Check if the app has the overlay permission
    private fun checkOverlayDisplayPermission(): Boolean {
        // If the SDK version is below Marshmallow (API 23), overlay permission is not needed
        return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(this)
    }
}

Output:



Next Article

Similar Reads