Creazione di una finestra di overlay di sistema (sempre in primo piano)


285

Sto cercando di creare un pulsante / immagine cliccabile sempre in primo piano che rimanga sempre in cima a tutte le finestre.

La prova del concetto è

Ho avuto successo e ho un servizio in esecuzione ora. Il servizio visualizza continuamente del testo nell'angolo in alto a sinistra dello schermo, mentre l'utente può interagire liberamente con le altre app in modo normale.

Quello che sto facendo è una sottoclasse ViewGroupe aggiungerla al gestore della finestra di root con flag TYPE_SYSTEM_OVERLAY. Ora voglio aggiungere un pulsante / immagine cliccabile al posto di questo testo che può ricevere eventi touch su se stesso. Ho provato a sovrascrivere "onTouchEvent" per l'intero, ViewGroupma non riceve alcun evento.

Come posso ricevere eventi solo su alcune parti del mio gruppo di visualizzazione sempre in primo piano? Si prega di suggerire

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;
    }
}

2
@coreSOLO, spero che tu abbia la risposta, le mie domande stranamente simili non hanno ricevuto alcuna risposta. :) +1
st0le

3
@ st0le prometto che passerò la notte e il giorno fino a quando non troverò la soluzione e la condividerò con te :)
coreSOLO

1
@ st0le Ok forse tu ed io possiamo scavare insieme, darmi un link alla tua domanda e fammi sapere quanti progressi sei stato in grado di fare ...
coreSOLO


3
È sorprendente che il tuo onDraw()venga chiamato. Non dovrebbe dispatchDraw()essere sostituito invece? Vedi groups.google.com/forum/?fromgroups#!topic/android-developers/…
faizal

Risposte:


158

Questa potrebbe essere una soluzione stupida. Ma funziona Se puoi migliorarlo, fammi sapere.

OnCreate del tuo servizio: ho usato WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCHflag. Questa è l'unica modifica del servizio.

@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);
    }

Ora inizierai a ricevere ogni singolo clic. Quindi, è necessario rettificare nel gestore dell'evento.

Nell'evento touch 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;
}

Inoltre potresti dover aggiungere questa autorizzazione al tuo manifest:

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

1
@pengwang: quali errori stai riscontrando? Questo codice non è indipendente, è necessario inserirli nel progetto con nomi file appropriati nel progetto appropriato.
Sarwar Erfan,

4
@pengwang: trova l'implementazione più semplice qui: docs.google.com/…
Sarwar Erfan,

6
l'intero codice è corretto, trovo il mio errore, ho dimenticato il link <usi-permesso android: nome = "android.permission.SYSTEM_ALERT_WINDOW" /> Sarwar Erfan penso che modifichi la tua risposta, può diventare più meraviglioso
pengwang

1
Questa risposta è molto utile, tranne una cosa. Come utilizzato nel codice, WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, secondo la documentazione, "non riceverà il gesto completo su / sposta / giù". In altre parole, non è possibile rilevare swipes o altro oltre a ACTION_DOWN. Bene, so che è possibile rilevare i passaggi perché Wave Launcher utilizza questo concetto simile e sono in grado di rilevare i passaggi. Qualcuno può spiegarmi come funziona?
Brian,

6
@SarwarErfan - L'ho usato perfettamente con la sua tappatura su 2.3 ma l'evento onTouch non è il geolocalizzazione invocato su Android 4.0, 1 ° 4.1. Per favore
aiutatemi

66

Seguendo la risposta di @Sam Lu, infatti Android 4.x blocca alcuni tipi dall'ascolto di eventi touch esterni, ma alcuni tipi, come ad esempio TYPE_SYSTEM_ALERT, fanno ancora il lavoro.

Esempio

    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);

permessi

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

5
Mi sta facendo impiccare il mio schermo. Qualsiasi idea
Viswanath Lekshmanan,

Ottimo post. Spero che questo non sia disabilitato nelle versioni future.
Cookster,

Le animazioni non funzioneranno su di esso ... :( E non è in grado di catturare i clic su qualsiasi vista in esso su 4.2.X. Qualche suggerimento?
Kamran Ahmed

Funziona ma quando sto usando quella scorciatoia (cioè Avviso a livello di sistema), le altre finestre di dialogo non vengono visualizzate. Perché ?
Chimu,

@Arju cosa intendi? stai cercando di rimuoverlo?
amirlazarovich,

18

A partire da Android 4.x, team di Android risolto un potenziale problema di sicurezza con l'aggiunta di una nuova funzione adjustWindowParamsLw()in cui si aggiungerà FLAG_NOT_FOCUSABLE, FLAG_NOT_TOUCHABLEe rimuovere FLAG_WATCH_OUTSIDE_TOUCHle bandiere per TYPE_SYSTEM_OVERLAYle finestre.

Cioè, una TYPE_SYSTEM_OVERLAYfinestra non riceverà alcun evento touch sulla piattaforma ICS e, naturalmente, l'uso TYPE_SYSTEM_OVERLAYnon è una soluzione praticabile per ICS e dispositivi futuri.


4
dunque quali sono le alternative?
Radhoo,


13

Sono uno degli sviluppatori di Tooleap SDK . Forniamo anche un modo per gli sviluppatori di visualizzare sempre in primo piano finestre e pulsanti, e abbiamo affrontato una situazione simile.

Un problema che le risposte qui non sono state risolte è quello dei "pulsanti sicuri" di Android.

I pulsanti protetti hanno la filterTouchesWhenObscuredproprietà, il che significa che non possono interagire con loro, se posizionati sotto una finestra, anche se quella finestra non riceve alcun tocco. Citando la documentazione di Android:

Specifica se filtrare i tocchi quando la finestra della vista è oscurata da un'altra finestra visibile. Se impostato su true, la vista non riceverà tocchi ogni volta che un brindisi, una finestra di dialogo o un'altra finestra vengono visualizzati sopra la finestra della vista. Fare riferimento alla documentazione di sicurezza {@link android.view.View} per maggiori dettagli.

Un esempio di tale pulsante è il pulsante di installazione quando si tenta di installare apk di terze parti. Qualsiasi app può visualizzare tale pulsante se si aggiunge al layout della vista la seguente riga:

android:filterTouchesWhenObscured="true"

Se si visualizza una finestra sempre in primo piano su un "pulsante protetto", tutte le parti dei pulsanti protette coperte da un overlay non gestiranno alcun tocco, anche se tale overlay non è selezionabile. Quindi, se stai pianificando di visualizzare una finestra del genere, dovresti fornire all'utente un modo per spostarla o eliminarla. E se una parte del tuo overlay è trasparente, tieni presente che l'utente potrebbe essere confuso perché un certo pulsante nell'app sottostante non funziona all'improvviso per lui.


Potete per favore rispondere alla mia domanda: stackoverflow.com/questions/28964771/...
Nauman Afzaal

c'è qualche attività in Android 10 che la vista overlay non può mostrare sopra di loro puoi per favore dire il motivo o vedere la mia domanda qui sarà molto utile stackoverflow.com/questions/59598264/…
Mateen Chaudhry

12

FUNZIONANDO SEMPRE SUL PULSANTE IMMAGINE SUPERIORE

prima di tutto scusa per il mio inglese

modifico i tuoi codici e faccio in modo che il pulsante immagine di lavoro che ascolta il suo evento touch non dia il controllo touch ai suoi elementi di sfondo.

inoltre offre agli ascoltatori di tocchi altri elementi

le combinazioni di pulsanti sono in basso e a sinistra

puoi inseguire alleanze ma devi inseguire coordinati nell'evento touch nell'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;
    }
}

Funziona, ma come posso assicurarmi che la mia immagine sia stata cliccata e non qualcosa attorno all'immagine?
Liam W,

@LiamW, le coordinate del tocco vengono confrontate con kangaroo.getWidth () in questo esempio. Puoi dedurre a cosa confrontarlo nel tuo codice in base a dove stai disegnando la tua immagine.
Evgenij Simkin il

Molto bella! Funziona perfettamente.
Evgenij Simkin il

Qual è la versione minima di Android su cui funziona? Sto lavorando a scrivere questo, ma sono nuovo per Android, quindi sto avendo i principianti.
Noitidart,

6

In realtà, puoi provare WindowManager.LayoutParams.TYPE_SYSTEM_ERROR invece di TYPE_SYSTEM_OVERLAY. Può sembrare un trucco, ma ti consente di visualizzare la vista sopra tutto e ottenere comunque eventi touch.


1
Ho provato di tutto per farlo funzionare, ma senza successo .... ma l'aggiunta di TYPE_SYSTEM_ERROR ha fatto il lavoro .... In realtà TYPE_SYSTEM_OVERLAY stava bloccando il tocco ..... + 1.
Robi Kumar Tomar,

6

TYPE_SYSTEM_OVERLAY Questa costante è stata deprecata a partire dal livello API 26. Utilizzare invece TYPE_APPLICATION_OVERLAY. o ** per gli utenti al di sotto e al di sopra di 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;
}

5

Prova questo. Funziona bene in ICS. Se si desidera interrompere il servizio, fare semplicemente clic sulla notifica generata nella barra di stato.

 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); 
    }
}

AGGIORNARE

Esempio qui

Per creare una vista overlay, quando si imposta LayoutParams NON impostare il tipo su TYPE_SYSTEM_OVERLAY.

Instead set it to TYPE_PHONE.

Use the following flags:

FLAG_NOT_TOUCH_MODAL

FLAG_WATCH_OUTSIDE_TOUCH

Questo non funziona per me, il mio schermo non interagisce con lo sfondo. Qualsiasi altro metodo che conosci ...
Vinuthan,

@Vinuthan Qual è il tuo risultato, risponde
Viswanath Lekshmanan,

No, non risponde. Ho completato la mia attività sopra la metà dello schermo in modo da poter interagire con lo sfondo, ma non posso interagire con lo sfondo.
Vinuthan,

FLAG_WATCH_OUTSIDE_TOUCH ti impedisce di interagire con lo sfondo
Richard Le Mesurier,

1
TYPE_PHONE ha funzionato per me - ora i tocchi vengono consegnati - almeno sono in grado di toccare un pulsante;) grazie!
vir us

3

Ecco una semplice soluzione, tutto ciò che serve è gonfiare il layout XML proprio come si fa con gli adattatori di elenco, basta fare il layout XML per gonfiarlo. Ecco il codice di cui hai bisogno.

 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;
    }

}



1

Bene, prova il mio codice, almeno ti dà una stringa come overlay, puoi benissimo sostituirlo con un pulsante o un'immagine. Non crederai che questa sia la mia prima app Android LOL. Ad ogni modo, se hai più esperienza con le app Android di me, prova

  • modifica dei parametri 2 e 3 in "new WindowManager.LayoutParams"
  • prova un approccio diverso all'evento

alla fine non ho trovato il tempo per perseguire questo, quindi sono ancora scarsi sui suoi dettagli ...
st0le

1

Se qualcuno sta ancora leggendo questo thread e non è in grado di farlo funzionare, mi dispiace molto dirti in questo modo di intercettare l'evento di movimento è considerato un bug e risolto in Android> = 4.2.

L'evento di movimento che hai intercettato, sebbene abbia un'azione come ACTION_OUTSIDE, restituisce 0 in getX e getY. Ciò significa che non puoi vedere tutta la posizione del movimento sullo schermo, né puoi fare nulla. So che il documento ha detto che otterrà xey, ma la verità è che NON lo farà. Sembra che questo blocchi il key logger.

Se qualcuno ha una soluzione alternativa, lascia il tuo commento.

ref: Perché ACTION_OUTSIDE restituisce 0 ogni volta su KitKat 4.4.2?

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


1

utilizzando il servizio è possibile ottenere questo:

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;
        }
    }
}

1

La risposta di @Sarwar Erfan non funziona più poiché Android non consente l'aggiunta di una vista con WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY alla finestra per essere più toccabile, nemmeno con WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH.

Ho trovato una soluzione a questo problema. Puoi verificarlo nella seguente domanda

Quando si aggiunge la vista alla finestra con WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, non viene visualizzato l'evento touch


Anche la tua soluzione indicata non funziona in Marshmallow
Ahmad Shahwaiz,

@AhmadShahwaiz Per favore, controlla di nuovo il link Ho aggiunto un commento per il problema che hai menzionato lì
patilmandar2007

Sì, ora funziona. Ma non ottenere la risposta di richiamata dopo aver chiamato startActivityForResult (intent, OVERLAY_REQ_CODE); nel metodo void protetto onActivityResult (int requestCode, int resultCode, Intent data).
Ahmad Shahwaiz,

@AhmadShahwaiz Le modifiche menzionate nel collegamento devono essere chiamate utilizzando l'attività in cui si ottiene la richiamata nel metodo onActivityResult. Se si sta verificando l'autorizzazione sopra in Servizio, potrebbe essere necessario aggiungere un'attività fittizia trasparente da avviare dal servizio, che può richiedere l'autorizzazione all'utente e quindi nell'attività fittizia onActivityResult si otterrà il risultato dall'utente. Dopo aver richiesto di notificare al servizio di aggiungere la vista alla finestra o meno a seconda della risposta dell'utente
patilmandar2007

1

Questa è una vecchia domanda ma recentemente Android ha un supporto per Bubbles. Le bolle verranno presto lanciate, ma attualmente gli sviluppatori possono iniziare a usarle e sono progettate per essere un'alternativa all'utilizzo SYSTEM_ALERT_WINDOW. App come (Facebook Messenger e MusiXMatch usano lo stesso concetto).

bolle

Le bolle vengono create tramite l'API di notifica, si invia la notifica normalmente. Se vuoi che bolle, devi allegare alcuni dati extra ad esso. Per ulteriori informazioni su Bubbles puoi consultare la Guida per gli sviluppatori Android ufficiale su Bubbles .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.