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.
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 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.