Crear una ventana de superposición del sistema (siempre en la parte superior)

Estoy tratando de crear un botón / imagen en la que se pueda hacer clic siempre en la parte superior que permanezca en la parte superior de todas las ventanas todo el tiempo.

La prueba de concepto es

He tenido éxito y ahora tengo un servicio en funcionamiento. El servicio muestra algo de texto en la esquina superior izquierda de la pantalla todo el tiempo, mientras que el usuario puede interactuar libremente con el resto de aplicaciones de manera normal.

Lo que estoy haciendo es una subclase ViewGroup y agréguelo al administrador de ventanas raíz con la bandera TYPE_SYSTEM_OVERLAY. Ahora quiero agregar un botón / imagen en la que se puede hacer clic en lugar de este texto que puede recibir eventos táctiles en sí mismo. Intenté anular "onTouchEvent" para todo ViewGroup pero no recibe ningún evento.

¿Cómo puedo recibir eventos solo en ciertas partes de mi grupo de vista siempre visible? Sugiera amablemente.

public class HUD extends Service {
    HUDView mView;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();
        mView = new HUDView(this);
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                0,
//              WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
//                      | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                PixelFormat.TRANSLUCENT);
        params.gravity = Gravity.RIGHT | Gravity.TOP;
        params.setTitle("Load Average");
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(mView, params);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(getBaseContext(),"onDestroy", Toast.LENGTH_LONG).show();
        if(mView != null)
        {
            ((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(mView);
            mView = null;
        }
    }
}

class HUDView extends ViewGroup {
    private Paint mLoadPaint;

    public HUDView(Context context) {
        super(context);
        Toast.makeText(getContext(),"HUDView", Toast.LENGTH_LONG).show();

        mLoadPaint = new Paint();
        mLoadPaint.setAntiAlias(true);
        mLoadPaint.setTextSize(10);
        mLoadPaint.setARGB(255, 255, 0, 0);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawText("Hello World", 5, 15, mLoadPaint);
    }

    @Override
    protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //return super.onTouchEvent(event);
        Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();
        return true;
    }
}

preguntado el 18 de diciembre de 10 a las 22:12

@coreSOLO, espero que obtengas tu respuesta, mis preguntas extrañamente similares no obtuvieron ninguna respuesta. :) +1 -

@ st0le te prometo que pasaré mi noche y mi día hasta que encuentre la solución y la comparta contigo :) -

@ st0le Ok, tal vez tú y yo podamos investigar juntos, dame un enlace de tu pregunta y hazme saber cuánto progreso pudiste hacer ... -

Es sorprendente que tu onDraw() está siendo llamado. No debería dispatchDraw() ser anulado en su lugar? Ver groups.google.com/forum/?fromgroups#!topic/android-developers/… -

16 Respuestas

Esta podría ser una solución estúpida. Pero funciona. Si puede mejorarlo, hágamelo saber.

OnCreate of your Service: he utilizado WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH bandera. Este es el único cambio en el servicio.

@Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();
        mView = new HUDView(this);
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                PixelFormat.TRANSLUCENT);
        params.gravity = Gravity.RIGHT | Gravity.TOP;
        params.setTitle("Load Average");
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(mView, params);
    }

Ahora, comenzará a recibir todos y cada uno de los eventos de clic. Por lo tanto, debe rectificar en su controlador de eventos.

En su evento táctil ViewGroup

@Override
public boolean onTouchEvent(MotionEvent event) {

    // ATTENTION: GET THE X,Y OF EVENT FROM THE PARAMETER
    // THEN CHECK IF THAT IS INSIDE YOUR DESIRED AREA


    Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();
    return true;
}

También es posible que deba agregar este permiso a su manifiesto:

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

contestado el 06 de mayo de 15 a las 19:05

@pengwang: ¿qué errores está recibiendo? Este código no es independiente, debe colocarlos en su proyecto con los nombres de archivo apropiados en el proyecto apropiado. - Sarwar Erfán

@pengwang: Encuentre la implementación más simple aquí: docs.google.com/… - Sarwar Erfán

todo el código es correcto, encuentro mi error, olvido el enlace Sarwar Erfan, creo que editas tu respuesta, puede volverse más maravilloso - Pengwang

@SarwarErfan: utilicé esto, se encorcha perfectamente en 2.3, pero el evento onTouch no se activa en Android 4.0, 1nd 4.1. Por favor ayuda - Sanjay Singh

Desde Android Oreo 8.0 y posteriores, no puede usar los siguientes tipos de ventana: TYPE_PHONE, TYPE_PRIORITY_PHONE, TYPE_SYSTEM_ALERT, TYPE_SYSTEM_OVERLAY, TYPE_SYSTEM_ERROR. Tendrá que usar TYPE_APPLICATION_OVERLAY y no se podrá arrastrar. - Fivos

Siguiendo la respuesta de @Sam Lu, de hecho Android 4.x bloquea ciertos tipos para que no escuchen eventos táctiles externos, pero algunos tipos, como TYPE_SYSTEM_ALERT, todavía hacer el trabajo.

Ejemplo

    WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            PixelFormat.TRANSLUCENT);

    WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
    LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
    View myView = inflater.inflate(R.layout.my_view, null);
    myView.setOnTouchListener(new OnTouchListener() {
       @Override
       public boolean onTouch(View v, MotionEvent event) {
           Log.d(TAG, "touch me");
           return true;
       }
     });

    // Add layout to window manager
    wm.addView(myView, params);

Permissions

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

contestado el 06 de mayo de 15 a las 19:05

Está colgando mi pantalla ... Alguna idea - Viswanath Lekshmanan

Buena publicación. Con suerte, esto tampoco estará deshabilitado en futuras versiones. - Cocinero

Las animaciones no funcionan en él ... :( Y no puede captar clics en ninguna vista en 4.2.X. ¿Alguna sugerencia? - Kamran Ahmed

Funciona, pero cuando estoy usando ese acceso directo (es decir, alerta de nivel del sistema), no se muestran otros cuadros de diálogo. Por qué ? - Chimú

@Arju ¿a qué te refieres? ¿Estás intentando eliminarlo? - amirlazarovich

A partir de Android 4.x, el equipo de Android solucionó un posible problema de seguridad al agregar una nueva función adjustWindowParamsLw() en el que se sumará FLAG_NOT_FOCUSABLE, FLAG_NOT_TOUCHABLE y quitar FLAG_WATCH_OUTSIDE_TOUCH banderas para TYPE_SYSTEM_OVERLAY ventanas

Eso es un TYPE_SYSTEM_OVERLAY la ventana no recibirá ningún evento táctil en la plataforma ICS y, por supuesto, para usar TYPE_SYSTEM_OVERLAY no es una solución viable para ICS y dispositivos futuros.

Respondido el 07 de Septiembre de 14 a las 05:09

¿Entonces cuales son las alternativas? - radhoo

Soy uno de los desarrolladores de SDK de Tooleap. También proporcionamos una forma para que los desarrolladores muestren siempre las ventanas y los botones superiores, y hemos lidiado con una situación similar.

Un problema que las respuestas aquí no han abordado es el de los "botones protegidos" de Android.

Los botones asegurados tienen filterTouchesWhenObscured propiedad, lo que significa que no se puede interactuar con ellos, si se colocan debajo de una ventana, incluso si esa ventana no recibe ningún toque. Citando la documentación de Android:

Especifica si se deben filtrar los toques cuando la ventana de la vista está oscurecida por otra ventana visible. Cuando se establece en verdadero, la vista no recibirá toques cada vez que aparezca un brindis, un diálogo u otra ventana sobre la ventana de la vista. Consulte la documentación de seguridad de {@link android.view.View} para obtener más detalles.

Un ejemplo de tal botón es el instalar cuando intente instalar apks de terceros. Cualquier aplicación puede mostrar dicho botón si agrega al diseño de la vista la siguiente línea:

android:filterTouchesWhenObscured="true"

Si muestra una ventana siempre en la parte superior sobre un "Botón protegido", todas las partes del botón protegido que están cubiertas por una superposición no manejarán ningún toque, incluso si no se puede hacer clic en esa superposición. Por lo tanto, si planea mostrar una ventana de este tipo, debe proporcionar una forma para que el usuario la mueva o la descarte. Y si una parte de su superposición es transparente, tenga en cuenta que su usuario podría estar confundido por qué un determinado botón en la aplicación subyacente no funciona para él de repente.

Respondido el 27 de diciembre de 15 a las 15:12

¿Puedes responder a mi pregunta? stackoverflow.com/questions/28964771/… - Nauman Afzaal

hay alguna actividad en Android 10 que la vista de superposición no puede mostrar encima de ellos, ¿puede decir el motivo o ver mi pregunta aquí? Será muy útil stackoverflow.com/questions/59598264/… - mateen chaudhry

TRABAJANDO SIEMPRE EN EL BOTÓN DE IMAGEN SUPERIOR

primero que nada perdon por mi ingles

Edito tus códigos y hago que el botón de imagen de trabajo que escucha su evento táctil no le dé control táctil a sus elementos de fondo.

también da a los oyentes un toque de otros elementos

las alineaciones de los botones están abajo y a la izquierda

puede cambiar las alineaciones pero necesita cambiar las cordinats en el evento táctil en el elemento if

import android.annotation.SuppressLint;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Toast;

public class HepUstte extends Service {
    HUDView mView;

    @Override
    public void onCreate() {
        super.onCreate();   

        Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();

        final Bitmap kangoo = BitmapFactory.decodeResource(getResources(),
                R.drawable.logo_l);


        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                kangoo.getWidth(), 
                kangoo.getHeight(),
                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                |WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                 PixelFormat.TRANSLUCENT);






        params.gravity = Gravity.LEFT | Gravity.BOTTOM;
        params.setTitle("Load Average");
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);



        mView = new HUDView(this,kangoo);

        mView.setOnTouchListener(new OnTouchListener() {


            @Override
            public boolean onTouch(View arg0, MotionEvent arg1) {
                // TODO Auto-generated method stub
                //Log.e("kordinatlar", arg1.getX()+":"+arg1.getY()+":"+display.getHeight()+":"+kangoo.getHeight());
                if(arg1.getX()<kangoo.getWidth() & arg1.getY()>0)
                {
                 Log.d("tıklandı", "touch me");
                }
                return false;
            }
             });


        wm.addView(mView, params);



        }



    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

}



@SuppressLint("DrawAllocation")
class HUDView extends ViewGroup {


    Bitmap kangoo;

    public HUDView(Context context,Bitmap kangoo) {
        super(context);

        this.kangoo=kangoo;



    }


    protected void onDraw(Canvas canvas) {
        //super.onDraw(canvas);


        // delete below line if you want transparent back color, but to understand the sizes use back color
        canvas.drawColor(Color.BLACK);

        canvas.drawBitmap(kangoo,0 , 0, null); 


        //canvas.drawText("Hello World", 5, 15, mLoadPaint);

    }


    protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
    }

    public boolean onTouchEvent(MotionEvent event) {
        //return super.onTouchEvent(event);
       // Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();

        return true;
    }
}

contestado el 10 de mayo de 13 a las 01:05

Esto funciona, pero ¿cómo puedo asegurarme de que se hizo clic en mi imagen y no en algo alrededor de la imagen? - Liam W.

@LiamW, las coordenadas del toque se comparan con kangaroo.getWidth () en este ejemplo. Puede deducir con qué compararlo en su propio código en función de dónde está dibujando su imagen. - Yevgeny Simkin

¡Muy agradable! Funciona perfectamente. - Yevgeny Simkin

¿Cuál es la versión mínima de Android en la que funciona? Estoy trabajando en escribir esto, pero soy nuevo en Android, así que tengo tiempo para principiantes. - Noitidart

TYPE_SYSTEM_OVERLAY Esta constante quedó obsoleta desde el nivel de API 26. Utilice TYPE_APPLICATION_OVERLAY en su lugar. o ** para usuarios por debajo y por encima de Android 8

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
    LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}

Respondido 06 Jul 19, 10:07

En realidad, puede probar WindowManager.LayoutParams.TYPE_SYSTEM_ERROR en lugar de TYPE_SYSTEM_OVERLAY. Puede parecer un truco, pero le permite mostrar la vista encima de todo y aún así obtener eventos táctiles.

respondido 11 nov., 15:09

Intenté todo para que funcionara, pero no tuve éxito ... pero agregando TYPE_SYSTEM_ERROR hizo el trabajo ... En realidad, TYPE_SYSTEM_OVERLAY estaba bloqueando el toque ..... + 1. - Robi Kumar Tomar

Prueba esto. Funciona bien en ICS. Si desea detener el servicio, simplemente haga clic en la notificación generada en la barra de estado.

 public class HUD extends Service
 {
    protected boolean foreground = false;
    protected boolean cancelNotification = false;
    private Notification notification;
    private View myView;
    protected int id = 0;
    private WindowManager wm;
    private WindowManager.LayoutParams params;
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    public void onCreate() {
        super.onCreate();
       // System.exit(0);
        Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_SHORT).show();
        params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
        params.gravity=Gravity.TOP|Gravity.LEFT;
    wm = (WindowManager) getSystemService(WINDOW_SERVICE);
    inflateview();
    foregroundNotification(1);
    //moveToForeground(1,n,true);
    }     
   @Override
    public void onDestroy() {
        super.onDestroy();
        ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(0);
        Toast.makeText(getBaseContext(),"onDestroy", Toast.LENGTH_SHORT).show();
        if(myView != null)
        {
            ((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(myView);
            myView = null;
        }
    }
    protected Notification foregroundNotification(int notificationId) 
   {    
    notification = new Notification(R.drawable.ic_launcher, "my Notification", System.currentTimeMillis());    
        notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT | Notification.FLAG_ONLY_ALERT_ONCE;   
        notification.setLatestEventInfo(this, "my Notification", "my Notification", notificationIntent());          
        ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).notify(id, notification);            
        return notification;
    }
    private PendingIntent notificationIntent() {
        Intent intent = new Intent(this, stopservice.class);    
        PendingIntent pending = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);    
        return pending;
    }
    public void inflateview()
    {
         LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
            myView = inflater.inflate(R.layout.activity_button, null);
            myView.setOnTouchListener(new OnTouchListener() {
               @Override
               public boolean onTouch(View v, MotionEvent event) {
                   Toast.makeText(getBaseContext(),"onToasttt", Toast.LENGTH_SHORT).show();
                   return false;
               }
             });
            // Add layout to window manager
            wm.addView(myView, params); 
    }
}

ACTUALIZACIÓN

Muestra aquí

Para crear una vista de superposición, al configurar LayoutParams NO establezca el tipo en TYPE_SYSTEM_OVERLAY.

Instead set it to TYPE_PHONE.

Use the following flags:

FLAG_NOT_TOUCH_MODAL

FLAG_WATCH_OUTSIDE_TOUCH

Respondido el 13 de diciembre de 13 a las 05:12

Esto no me funciona, mi pantalla no interactúa con el fondo. Cualquier otro método que conozcas ... - Vinuthán

@Vinuthan ¿Cuál es su salida, responde? Viswanath Lekshmanan

No, no responde. He acolchado mi actividad arriba a la mitad de la pantalla para poder interactuar con el fondo, pero no puedo interactuar con el fondo. - Vinuthán

FLAG_WATCH_OUTSIDE_TOUCH le impide interactuar con el fondo - Richard Le Mésurier

TYPE_PHONE funcionó para mí, ahora se entregan los toques, al menos puedo tocar un botón;) ¡gracias! - virus

Encontré una biblioteca que hace precisamente eso: https://github.com/recruit-lifestyle/FloatingView

Hay un proyecto de muestra en la carpeta raíz. Lo ejecuté y funciona según lo requerido. Se puede hacer clic en el fondo, incluso si es otra aplicación.

enter image description here

Respondido el 04 de Septiembre de 18 a las 07:09

Gracias por la recomendación, solo estaba tratando de encontrar este gran proyecto. - subiendo

Aquí hay una solución simple. Todo lo que necesita es inflar el diseño XML tal como lo hace en los adaptadores de lista, simplemente haga un diseño XML para inflarlo. Aquí está el código que todo lo que necesita.

 public class HUD extends Service {
    View mView;

    LayoutInflater inflate;
    TextView t;
    Button b;

    @Override
    public void onCreate() {
        super.onCreate();   

        Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();


        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);

        Display display = wm.getDefaultDisplay();  get phone display size
        int width = display.getWidth();  // deprecated - get phone display width
        int height = display.getHeight(); // deprecated - get phone display height 


        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                width, 
                height,
                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                |WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                 PixelFormat.TRANSLUCENT);


        params.gravity = Gravity.LEFT | Gravity.CENTER;
        params.setTitle("Load Average");

        inflate = (LayoutInflater) getBaseContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        mView = inflate.inflate(R.layout.canvas, null);

        b =  (Button) mView.findViewById(R.id.button1);
        t = (TextView) mView.findViewById(R.id.textView1);
        b.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {
            // TODO Auto-generated method stub
            t.setText("yes you click me ");
        }
       });

        wm.addView(mView, params);

        }



    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

}

Respondido el 01 de diciembre de 16 a las 11:12

Utiliza el permiso "android.permission.SYSTEM_ALERT_WINDOW" tutorial completo en este enlace: http://androidsrc.net/facebook-chat-like-floating-chat-heads/

Respondido 05 Feb 15, 03:02

Esta es una pregunta antigua, pero recientemente Android tiene soporte para Bubbles. Pronto se lanzarán las burbujas, pero actualmente los desarrolladores pueden comenzar a usarlas. Están diseñadas para ser una alternativa al uso de SYSTEM_ALERT_WINDOW. Aplicaciones como (Facebook Messenger y MusiXMatch usan el mismo concepto).

Burbujas

Las burbujas se crean a través de la API de notificaciones, envía su notificación normalmente. Si desea que aparezca una burbuja, debe adjuntarle algunos datos adicionales. Para obtener más información sobre Bubbles puede dirigirse al oficial Guía para desarrolladores de Android sobre burbujas.

Respondido el 03 de junio de 20 a las 07:06

Bueno, prueba mi código, al menos te da una cadena como superposición, puedes reemplazarlo con un botón o una imagen. No creerás que esta es mi primera aplicación para Android LOL. De todos modos, si tiene más experiencia con las aplicaciones de Android que yo, intente

  • cambiando los parámetros 2 y 3 en "nuevo WindowManager.LayoutParams"
  • prueba un enfoque de evento diferente

Respondido el 19 de diciembre de 10 a las 10:12

Eventualmente no encontré tiempo para continuar con esto, por lo tanto, todavía soy escaso en sus detalles ... - robar

Si alguien sigue leyendo este hilo y no puede hacerlo funcionar, lamento mucho decirte que esta forma de interceptar el evento de movimiento se considera un error y se corrige en Android> = 4.2.

El evento de movimiento que interceptó, aunque tiene acción como ACTION_OUTSIDE, devuelve 0 en getX y getY. Esto significa que no puede ver toda la posición de movimiento en la pantalla, ni puede hacer nada. Sé que el médico dijo que obtendrá xey, pero la verdad es que NO. Parece que esto es para bloquear el registrador de teclas.

Si alguien tiene una solución alternativa, deje su comentario.

árbitro: ¿Por qué ACTION_OUTSIDE devuelve 0 siempre en KitKat 4.4.2?

https://code.google.com/p/android/issues/detail?id=72746

contestado el 23 de mayo de 17 a las 13:05

al usar el servicio, puede lograr esto:

public class PopupService extends Service{

    private static final String TAG = PopupService.class.getSimpleName();
    WindowManager mWindowManager;
    View mView;
    String type ;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
//        registerOverlayReceiver();
        type = intent.getStringExtra("type");
        Utils.printLog("type = "+type);
        showDialog(intent.getStringExtra("msg"));
        return super.onStartCommand(intent, flags, startId);
    }

    private void showDialog(String aTitle)
    {
        if(type.equals("when screen is off") | type.equals("always"))
        {
            Utils.printLog("type = "+type);
            PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
            WakeLock mWakeLock = pm.newWakeLock((PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "YourServie");
            mWakeLock.acquire();
            mWakeLock.release();
        }

        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        mView = View.inflate(getApplicationContext(), R.layout.dialog_popup_notification_received, null);
        mView.setTag(TAG);

        int top = getApplicationContext().getResources().getDisplayMetrics().heightPixels / 2;

        LinearLayout dialog = (LinearLayout) mView.findViewById(R.id.pop_exit);
//        android.widget.LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) dialog.getLayoutParams();
//        lp.topMargin = top;
//        lp.bottomMargin = top;
//        mView.setLayoutParams(lp);

        final EditText etMassage = (EditText) mView.findViewById(R.id.editTextInPopupMessageReceived);

        ImageButton imageButtonSend = (ImageButton) mView.findViewById(R.id.imageButtonSendInPopupMessageReceived);
//        lp = (LayoutParams) imageButton.getLayoutParams();
//        lp.topMargin = top - 58;
//        imageButton.setLayoutParams(lp);
        imageButtonSend.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Utils.printLog("clicked");
//                mView.setVisibility(View.INVISIBLE);
                if(!etMassage.getText().toString().equals(""))
                {
                    Utils.printLog("sent");
                    etMassage.setText("");
                }
            }
        });

        TextView close = (TextView) mView.findViewById(R.id.TextViewCloseInPopupMessageReceived);
        close.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                hideDialog();   
            }
        });

        TextView view = (TextView) mView.findViewById(R.id.textviewViewInPopupMessageReceived);
        view.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                hideDialog();   
            }
        });

        TextView message = (TextView) mView.findViewById(R.id.TextViewMessageInPopupMessageReceived);
        message.setText(aTitle);

        final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
        WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
//                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON ,
        PixelFormat.RGBA_8888);

        mView.setVisibility(View.VISIBLE);
        mWindowManager.addView(mView, mLayoutParams);
        mWindowManager.updateViewLayout(mView, mLayoutParams);

    }

    private void hideDialog(){
        if(mView != null && mWindowManager != null){
            mWindowManager.removeView(mView);
            mView = null;
        }
    }
}

Respondido 27 Feb 15, 09:02

La respuesta de @Sarwar Erfan ya no funciona ya que Android no permite agregar vista con WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY a la ventana para que se pueda tocar más, ni siquiera con WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH.

Encontré solución a este problema. Puedes comprobarlo en la siguiente pregunta.

Al agregar una vista a la ventana con WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, no se obtiene un evento táctil

contestado el 23 de mayo de 17 a las 12:05

Su solución recomendada tampoco funciona en Marshmallow - Ahmad Shahwaiz

@AhmadShahwaiz Por favor, revise el enlace nuevamente. He agregado un comentario para el problema que mencionó allí. patilmandar2007

Sí, ahora está funcionando. Pero no obtener la respuesta de devolución de llamada después de llamar a startActivityForResult (intent, OVERLAY_REQ_CODE); en el método protegido void onActivityResult (int requestCode, int resultCode, Intent data). - Ahmad Shahwaiz

@AhmadShahwaiz Los cambios mencionados en el enlace deben llamarse usando la actividad donde obtenemos la devolución de llamada en el método onActivityResult. Si está verificando el permiso anterior en el Servicio, es posible que deba agregar una actividad transparente ficticia para iniciar desde el servicio, que puede solicitar al usuario Permiso y luego, en la actividad ficticia onActivityResult, obtendrá el resultado del usuario. Después, deberá notificar a su servicio para agregar vista a la ventana o no, según la respuesta del usuario: patilmandar2007

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.