11

Devo implementare una finestra di sovrapposizione come l'app di Caller vera. Ma il problema che sto ottenendo è che, durante una chiamata in entrata o in uscita, il mio servizio si avvicina o distrugge automaticamente.Servizio finestra di sovrapposizione in Android

La classe di servizio

public class OverlayService extends Service implements View.OnClickListener,NotifyHardwareChanges,UpdateSoundDB{ 

private WindowManager windowManager; 
WindowManager.LayoutParams params; 
View view; 
Button btnEndCall; 
public static TextView textView; 
public static Context cntxt; 

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

@Override 
public int onStartCommand(Intent intent, int flags, int startId) { 
    // Let it continue running until it is stopped. 
    return START_NOT_STICKY; 
} 

@Override 
public void onCreate() { 
    super.onCreate(); 
    this.cntxt = getApplicationContext(); 
    windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); 

    params= new WindowManager.LayoutParams(
      WindowManager.LayoutParams.MATCH_PARENT, 
      WindowManager.LayoutParams.WRAP_CONTENT, 
      WindowManager.LayoutParams.TYPE_PHONE, 
      WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, 
      PixelFormat.TRANSLUCENT); 

    params.gravity = Gravity.CENTER; 
    params.x = 0; 
    params.y = 100; 

    LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    view = inflater.inflate(R.layout.list_item, null); 

    textView = (TextView) view.findViewById(R.id.textView); 

    btnEndCall = (Button) view.findViewById(R.id.end_call); 
    //btnEndCall.set 
    btnEndCall.setOnClickListener(this); 


    //this code is for dragging the chat head 
    view.setOnTouchListener(new View.OnTouchListener() { 
     private int initialX; 
     private int initialY; 
     private float initialTouchX; 
     private float initialTouchY; 

     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      switch (event.getAction()) { 
       case MotionEvent.ACTION_DOWN: 
        initialX = params.x; 
        initialY = params.y; 
        initialTouchX = event.getRawX(); 
        initialTouchY = event.getRawY(); 
        return true; 
       case MotionEvent.ACTION_UP: 
        return true; 
       case MotionEvent.ACTION_MOVE: 
        params.x = initialX 
          + (int) (event.getRawX() - initialTouchX); 
        params.y = initialY 
          + (int) (event.getRawY() - initialTouchY); 
        windowManager.updateViewLayout(view, params); 
        return true; 
      } 
      return false; 
     } 
    }); 

    windowManager.addView(view, params); 
    Utillities.start(OverlayService.this, 1, OverlayService.this); 
} 

@Override 
public void onDestroy() { 
    super.onDestroy(); 
    if (view != null) 
     windowManager.removeView(view); 

    Utillities.stop(OverlayService.this,1,OverlayService.this); 
} 

@Override 
public void onClick(View v) { 
    if(view!=null){ 
     Utillities.stop(OverlayService.this,1,OverlayService.this); 
     windowManager.removeView(view); 
     view = null; 
    } 
} 

@Override 
public void getNotify(String str) {} 

@Override 
public void setProcess(double signalEMA) { 
    int progress = ((int) signalEMA - Preferences.readInteger(getApplicationContext(), Preferences.CALIBRATION, 0)) ; 
    textView.setText("Your Sound Level :" + progress +"db"); 
    if ((Preferences.readInteger(cntxt, Preferences.SOUND_LEVEL, 0) > 0) && (progress > Preferences.readInteger(cntxt, Preferences.SOUND_LEVEL, 0))) { 
     textView.setTextColor(cntxt.getResources().getColor(R.color.red)); 
    }else{ 
     textView.setTextColor(cntxt.getResources().getColor(R.color.black)); 
    } 
} 

}

e qui segue è una BroadcastReceiver per rilevare le chiamate in entrata e in uscita e anche essere utilizzato per avviare e interrompere Overlayservice.

public class ServiceReceiver extends BroadcastReceiver{ 

    TelephonyManager telephonyManager; 

    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) @Override 
    public void onReceive(Context context, Intent intent) { 
     // TODO Auto-generated method stub 
     if(Preferences.readBoolean(context, Preferences.APP_ON_OFF, false) == true){ 
      //The other intent tells us the phone state changed. Here we set a listener to deal with it 
      TelephonyManager telephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); 
      telephony.listen(new PhonecallStartEndDetector(context), PhoneStateListener.LISTEN_CALL_STATE); 
     } 
    } 

    public class PhonecallStartEndDetector extends PhoneStateListener { 

     int lastState = TelephonyManager.CALL_STATE_IDLE; 
     boolean isIncoming; 
     Context cntx; 

     public PhonecallStartEndDetector(Context context) { 
      this.cntx = context; 
     } 

     //Incoming call- goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up 
     //Outgoing call- goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up 
     @Override 
     public void onCallStateChanged(int state, String incomingNumber) { 
      super.onCallStateChanged(state, incomingNumber); 
      if (lastState == state) { 
       //No change, debounce extras 
       return; 
      } 
      switch (state) { 
       case TelephonyManager.CALL_STATE_RINGING: 
        isIncoming = true; 
        //cntx.startService(new Intent(cntx, OverlayService.class)); 
        //Toast.makeText(cntx, "onIncomingCallStarted", Toast.LENGTH_SHORT).show(); 
        break; 
       case TelephonyManager.CALL_STATE_OFFHOOK: 
        //Transition of ringing->offhook are pickups of incoming calls. Nothing donw on them 
        if (lastState != TelephonyManager.CALL_STATE_RINGING) { 
         isIncoming = false; 
         cntx.startService(new Intent(cntx, OverlayService.class)); 
         //Toast.makeText(cntx, "onOutgoingCallStarted", Toast.LENGTH_SHORT).show(); 
        }else{ 
         isIncoming = true; 
         cntx.startService(new Intent(cntx, OverlayService.class)); 
        } 

        break; 
       case TelephonyManager.CALL_STATE_IDLE: 
        //Went to idle- this is the end of a call. What type depends on previous state(s) 
        if (lastState == TelephonyManager.CALL_STATE_RINGING) { 
         //Ring but no pickup- a miss 
         cntx.stopService(new Intent(cntx, OverlayService.class)); 
         //Toast.makeText(cntx, "onMissedCall", Toast.LENGTH_SHORT).show(); 
        } else if (isIncoming) { 
         cntx.stopService(new Intent(cntx, OverlayService.class)); 
         //Toast.makeText(cntx, "onIncomingCallEnded", Toast.LENGTH_SHORT).show(); 
        } else { 
         cntx.stopService(new Intent(cntx, OverlayService.class)); 
         //Toast.makeText(cntx, "onOutgoingCallEnded", Toast.LENGTH_SHORT).show(); 
        } 
        break; 
      } 
      lastState = state; 
     } 
    } 
} 
+0

Potresti postare lo stacktrace (utilizzando il debugger) sul metodo onDetachedFromWindow() della vista che aggiungi a window manager. Prova anche a modificare WindowManager.LayoutParams.TYPE_PHONE su TYPE_SYSTEM_ALERT e vedere se cambia qualcosa? –

+0

@TinTran, grazie per il vostro feedback. Devo mostrare un overlay dalla classe Service, quindi non so come ottenere stacktrace (usando il debugger) sul metodo onDetachedFromWindow() della vista che aggiungi a window manager. –

+0

Hai mai scritto una visualizzazione personalizzata? Hai provato a cambiare WindowManager.LayoutParams.TYPE_PHONE in TYPE_SYSTEM_ALERT –

risposta

1

Il servizio in primo piano ha priorità elevata, quindi provare a creare il servizio come servizio in primo piano e verificare se funziona. Per creare un servizio in primo piano è necessario fornire una notifica, in modo che gli utenti siano a conoscenza del fatto che è in corso un servizio in primo piano.

Ecco come si può creare un foreground service

Ma prima di effettuare la primo piano di servizio, eseguire il debug perché il vostro attuale servizio è sempre ucciso controllando i registri.

+0

Ciao Vins, grazie per la tua risposta. Puoi fornirmi un esempio. Poiché non sono a conoscenza del servizio in primo piano. –

0

L'istanza di BroadcastReceiver verrà cancellata automaticamente dal sistema dopo che è stato ricevuto un tentativo. Quindi il servizio di telefonia referenziata verrà anche ucciso, rendendo il tuo attuale buggy di implementazione che a sua volta in determinate condizioni in base all'attuale implementazione chiamerà il servizio di stop e il servizio verrebbe distrutto. Ascolta le modifiche alle chiamate e per ogni intento ricevuto estrai le informazioni e passa al servizio e gestiscile lì.

Problemi correlati