Bueno, en nuestras computadoras de escritorio podemos restaurar fácilmente las ventanas, hacer algo en segundo plano y maximizar la ventana cuando queramos. Pero no vemos mucho esta función en las aplicaciones de Android. Hoy en día podemos ver que Android ofrece pantalla dividida, pero esa es una función proporcionada por el sistema operativo, no la función individual de la aplicación. Hagamos una aplicación que pueda minimizarse y maximizarse con solo hacer clic en un botón. Esta función puede ayudar a los usuarios de muchas maneras. Suponga que está leyendo un documento pdf con algunos cálculos matemáticos y luego una calculadora minimizada sobre la aplicación de visor de pdf será muy útil. Hay muchas aplicaciones que usan esta función, como el Portapapeles, la Calculadora MI y muchas más. Aquí hay una demostración de la aplicación final de este artículo.
Implementación paso a paso
Paso 1: crear un nuevo proyecto
Para crear un nuevo proyecto en Android Studio, consulte Cómo crear/iniciar un nuevo proyecto en Android Studio . Tenga en cuenta que seleccione Java como lenguaje de programación.
Paso 2: Hagamos la plataforma de trabajo
- Agregue nuevos colores para la aplicación : vaya a valores -> colores.xml . Cualquier color personalizado se puede agregar aquí. Hemos añadido estos dos colores.
XML
<color name="gfgTheme">#FF2F8D46</color> <color name="gfgThemeTwo">#FF098043</color>
- Elimina la barra de acciones : en Android Studio 4.1, ve a valores -> temas . Hay dos archivos XML de temas, uno para el modo claro y otro para el modo oscuro . En ambos XML, en el bloque de estilo, cambie el atributo principal a Theme.MaterialComponents.DayNight.NoActionBar .
- Cambiar el color principal del tema para la aplicación : en el mismo archivo, el primer bloque de elementos debe ser sobre el color principal de la aplicación. Aquí se agregan los colores recién agregados. En el bloque de elementos, agregue @color/gfgTheme o @color/gfgThemeTwo .
Paso 3: primero hagamos todos los diseños
3.a: Empezar a trabajar en el archivo activity_main.xml
Este archivo XML hace el diseño de la actividad principal de la aplicación. El diseño no es tan complicado. Solo hay un Button , TextView , EditText y otro Button uno tras otro dentro de un ConstraintLayout. Aquí está el código XML.
XML
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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" 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: Comience a trabajar en el archivo floating_layout.xml
Vaya a res -> diseño . Haga clic con el botón derecho en diseño -> Nuevo -> Archivo de recursos de diseño . Agregue el nombre del diseño ( floating_layout aquí). Este archivo XML hace el diseño de la ventana flotante. Tiene los mismos componentes que el diseño principal pero con restricciones de tamaño ligeramente diferentes. Aquí está el código XML.
XML
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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="@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>
Paso 4: Comience a trabajar en los programas de Java
Hicimos 3 clases aquí. Obviamente, el primero es MainActivity . El segundo es FloatingWindowGFG para el servicio de ventana flotante y el último es una clase común para dos variables comunes.
4.a: Hagamos la clase para las variables comunes
- Para esto primero, hagamos un paquete llamado Common . Haga clic derecho en la ruta del paquete del proyecto ( com.wheic.floatingedittext aquí) -> Nuevo -> Paquete .
- Una ventana aparecerá. El nombre del paquete previsto está escrito ( común para mí). Se creará un nuevo paquete.
- Haga clic derecho en el paquete recién creado -> Nuevo -> Clase Java . El nombre de la clase prevista está escrito ( Común para aquí).
- Se crean dos variables de string públicas, una es currentDesc y otra se guarda Desc . Ambos se inician con strings vacías.
- Aquí está el código para la clase Common.java .
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: Comience a trabajar en el archivo MainActivity.java
- Primero, se crea la referencia para las clases de componentes. Se crean dos botones , un AlertDialog y una referencia EditText .
- Antes de ir a onCreate() , se crean algunos otros métodos.
- isMyServiceRunning() : este método ayuda a determinar si se está ejecutando el servicio de ventana flotante de esta aplicación. Esta función es necesaria cuando se abre la misma aplicación cuando ya se ve la ventana flotante porque entonces se necesita detener el servicio de ventana flotante. Aquí está el código con la explicación línea por línea:
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() : el método ayuda a redirigir la aplicación a la Configuración para habilitar ‘ Mostrar sobre otras aplicaciones ‘. Aunque para eso se debe agregar una línea adicional al archivo AndroidManifest.xml. Para eso, vaya a la aplicación -> manifiestos -> AndroidManifest.xml . Agregue esta línea antes del bloque de aplicación:
<usos-permiso 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() : este método en realidad verifica que si el nivel de la API es superior a 23, entonces si la ‘ Mostrar sobre otras aplicaciones ‘ está habilitada en la configuración. Aquí está el código de esta función:
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; } }
- Ahora aquí está el código completo para el archivo MainActivity.java .
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: Comience a trabajar en el archivo FloatingWindowGFG.java
- Se crea otra clase denominada FloatingWindowGFG . Vaya a la ruta del paquete del proyecto ( com.wheic.floatingedittext para mí) -> Nuevo -> Clase Java y luego se le da cualquier nombre previsto ( FloatingWindowGFG para mí).
- Esta clase hereda la clase Servicio.
- Ahora, como esta clase se hereda de la clase Servicio, esta clase se puede usar como un servicio en el archivo Manifiesto. Entonces, en AndroidManifest.xml , agregue esta línea después del bloque de actividad y antes de que finalice el bloque de aplicación.
<servicio android:name=”.FloatingWindowGFG”/>
- Ahora aquí está el código para FloatingWindowGFG.java . Se han añadido los comentarios para una mejor explicación:
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); } }
Producción:
Finalmente, el proyecto está listo. Puedes consultar este proyecto en este enlace de GitHub .