2013-03-06 8 views
9

Ho un servizio che avvia una sovrapposizione di sistema. Quando l'overlay è visibile, voglio che sia tangibile/rilevare tocchi, ma voglio preservare l'interazione con lo schermo dietro di esso (con dietro intendo l'attività sottostante, ad esempio l'overlay).Perché la sovrapposizione del sistema è in grado di catturare tutti i tocchi (non è possibile alcuna interazione con la vista sottostante)

Il mio overlay è un bitmap/PNG di 128x128px. Viene disegnato e quando clicco, ricevo il TOUCH! log, che è buono. Ma anche quando clicco su qualsiasi altra parte dello schermo (oltre all'overlay) ottengo il TOUCH! log e nessuna interazione con lo schermo sottostante è possibile.

Qui sono le parti del mio codice:

principale attività per avviare il servizio

buttonStart.setOnClickListener(new View.OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       // start Service and return to Homescreen 
       Intent i = new Intent(MainActivity.this, MyService.class); 
       startService(i);     

       Intent newActivity = new Intent(Intent.ACTION_MAIN); 
       newActivity.addCategory(Intent.CATEGORY_HOME); 
       newActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
       startActivity(newActivity); 
      } 
     }); 

Servizio/Mostra overlay

@Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 

     myOverlay = new Overlay(MyService.this); 

     WindowManager.LayoutParams params = new WindowManager.LayoutParams(
       WindowManager.LayoutParams.WRAP_CONTENT, 
       WindowManager.LayoutParams.WRAP_CONTENT, 
       WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, 
       WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | 
       WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, 
       PixelFormat.TRANSLUCENT); 
     params.gravity = Gravity.LEFT | Gravity.TOP; 

     wm = (WindowManager) getSystemService(WINDOW_SERVICE); 
     wm.addView(myOverlay, params); 

     myOverlay.setAnimation(new Waiting(MyService.this, 0, 0)); 
     myOverlay.postInvalidate(); 

     return super.onStartCommand(intent, flags, startId); 
    } 

Overlay

public MyOverlay(Context context) { 
     super(context);  
     this.context = context; 

     setOnTouchListener(new OnTouchListener() { 

      @Override 
      public boolean onTouch(View v, MotionEvent event) { 
       Log.i("TOUCH!", event.getAction() + ", x:"+event.getX()+", y:"+event.getY()); 
       return false; 
      } 
     }); 
    } 

Cosa sto sbagliando? Ho provato anche WindowManager.LayoutParams.TYPE_PHONE invece di WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, ma lo stesso comportamento.

Non sto utilizzando il flag FLAG_WATCH_OUTSIDE_TOUCH, quindi perché i tocchi non sono registrati accanto all'overlay?

EDIT

Sembra che ho trovato il problema, ma ancora non so come risolverlo se ... L'immagine visualizzata nella sovrapposizione è molto piccolo e non il problema, ma (!) la sovrapposizione stessa è a schermo intero

ho aggiunto il seguente registro alla sovraimpressione/onTouch() evento:

Log.i("TOUCH!", "View: "+v.toString() +", size="+ v.getWidth()+"/"+v.getHeight()); 

che poi mi dice Vista: package.overlay.myOverlay, size = 480/762

Ora ho provato a forzarlo a non essere a schermo pieno aggiungendo la seguente riga nel Servizio:

@Override 
     public int onStartCommand(Intent intent, int flags, int startId) { 

      myOverlay = new Overlay(MyService.this); 
//HERE 
myOVerlay.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); 

      WindowManager.LayoutParams params = new WindowManager.LayoutParams(
        WindowManager.LayoutParams.WRAP_CONTENT, 
        WindowManager.LayoutParams.WRAP_CONTENT, 
        WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, 
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | 
        WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, 
        PixelFormat.TRANSLUCENT); 
      params.gravity = Gravity.LEFT | Gravity.TOP; 

      wm = (WindowManager) getSystemService(WINDOW_SERVICE); 
      wm.addView(myOverlay, params); 

      myOverlay.setAnimation(new Waiting(MyService.this, 0, 0)); 
      myOverlay.postInvalidate(); 

      return super.onStartCommand(intent, flags, startId); 
     } 

Ma non aiuta ... ancora myoverlay ha la dimensione di 480x762 ... Perché è così grande e come posso ottenere che abbia le dimensioni dell'immagine contenuta?

+1

Quanto è grande il tuo overlay? Copre l'intero layout sottostante? È una cosa trasparente? – abbath

+1

"ma voglio preservare l'interazione con lo schermo dietro di esso" - fortunatamente, questo non è più possibile a partire da Android 4.0.3, per prevenire attacchi di tipo "tapjacking", almeno per i tocchi sulla sovrapposizione stessa. Una sovrapposizione può ricevere eventi di tocco (e quelli che non vengono inoltrati insieme) o non ricevere eventi di tocco (simili a un 'Toast'). – CommonsWare

+0

@abbath È una bitmap 128x128 px disegnata su una tela. Ha uno sfondo trasparente, sì, il che significa che probabilmente dovrei renderlo opaco per verificare se è davvero così piccolo ... lo proverò –

risposta

-2

Ho avuto lo stesso problema, solo cercare di aggiungere questo al codice:

WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY 

Sono abbastanza fiducioso il codice funzionerà, se non si limita a controllare il codice per alcuni altri errori, ma per quanto riguarda il tocco, questa è la soluzione. In ogni caso fammelo sapere. e ho quasi dimenticato la seconda parte, basta cambiare gli attributi in matchparent invece di wrapcontent.

Good Luck

+0

Penso che questo sia l'opposto di ciò che l'OP voleva, questo rende la tua vista catturare tutti i clic. – marmor

+1

@marmor, nelle ultime versioni di Android, la finestra 'TYPE_SYSTEM_OVERLAY' non può ricevere eventi di tocco. – Sam

2

Ho anche avuto lo stesso problema e ho risolto il problema impostare il params.width & params.height. Prova questo.

params.width = 128; 
params.height = 128; 

Spero che possa essere d'aiuto.

8

questo ha funzionato per me:

WindowManager.LayoutParams params = new WindowManager.LayoutParams(); 
params.height = WindowManager.LayoutParams.WRAP_CONTENT; 
params.width = WindowManager.LayoutParams.WRAP_CONTENT; 
params.type = WindowManager.LayoutParams.TYPE_TOAST; 
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 
    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 
    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 

utilizzare questa LayoutParams quando si aggiunge il View al WindowManager, che gli impedisce di avere ricevuto clic, è possibile che TYPE_TOAST è sufficiente, ma ho aggiunto bandiere solo per assicurarsi.

Problemi correlati