No se puede detectar cuando la llamada saliente se responde en Android

Para detectar cuándo se responde una llamada saliente, intenté crear un PhoneStateListener y escuchar los CALL_STATE_RINGING , CALL_STATE_OFFHOOK y CALL_STATE_IDLE de esta pregunta , pero parece que no funciona, como se explica a continuación.

Primero, registré el siguiente permiso en el manifiesto:

  

Luego, un BroadcastReceiver llamado OutCallLogger que capta el evento NEW_OUTGOING_CALL cada vez que se realiza una llamada saliente:

      

Luego, mi implementación de OutCallLogger . Configuré un booleano llamado noCallListenerYet para evitar adjuntar un nuevo PhoneStateListener al TelephonyManager cada vez que se invoca onReceive() .

 public class OutCallLogger extends BroadcastReceiver { private static boolean noCallListenerYet = true; @Override public void onReceive(final Context context, Intent intent) { number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); if (noCallListenerYet) { final TelephonyManager tm = (TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE); tm.listen(new PhoneStateListener() { @Override public void onCallStateChanged(int state, String incomingNumber) { switch (state) { case TelephonyManager.CALL_STATE_RINGING: Log.d(This.LOG_TAG, "RINGING"); break; case TelephonyManager.CALL_STATE_OFFHOOK: Log.d(This.LOG_TAG, "OFFHOOK"); break; case TelephonyManager.CALL_STATE_IDLE: Log.d(This.LOG_TAG, "IDLE"); break; default: Log.d(This.LOG_TAG, "Default: " + state); break; } } }, PhoneStateListener.LISTEN_CALL_STATE); noCallListenerYet = false; } } } 

Ahora, cuando realizo una llamada saliente en mi dispositivo, CALL_STATE_RINGING NUNCA se invoca. Siempre obtengo impresiones de “IDLE” a “OFFHOOK” cuando la otra línea comienza a sonar, nada cuando se responde la llamada, y una impresión de “IDLE” cuando la llamada finaliza.

¿Cómo puedo detectar de manera confiable cuándo se responde una llamada saliente en Android, o eso es posible?

Desde Android 5.0, esto es posible para las aplicaciones del sistema. Pero necesitas usar la API oculta de Android.

Lo tengo para que funcione así:

  
      
 public class OutCallLogger extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { switch (intent.getIntExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, -2) { case PreciseCallState.PRECISE_CALL_STATE_IDLE: Log.d(This.LOG_TAG, "IDLE"); break; case PreciseCallState.PRECISE_CALL_STATE_DIALING: Log.d(This.LOG_TAG, "DIALING"); break; case PreciseCallState.PRECISE_CALL_STATE_ALERTING: Log.d(This.LOG_TAG, "ALERTING"); break; case PreciseCallState.PRECISE_CALL_STATE_ACTIVE: Log.d(This.LOG_TAG, "ACTIVE"); break; } } } 

Puede encontrar todos los estados de llamada posibles en PreciseCallState.java y todos los extras que el bash contiene en TelephonyRegistry.java .

Parece que el estado TIMBRE se alcanza solo por las llamadas entrantes. Las llamadas salientes cambian de IDLE a OFFHOOK, por lo que es posible que no sea posible mirar el estado del teléfono.

Creo que podría ser posible usar funciones internas, mira esto: ¿qué representan los diferentes estados de llamada en la stack de telefonía de Android?

Tal vez intente utilizar CallManager? Consulte http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3.3_r1/com/android/internal/telephony/CallManager.java . También encontré CallManager.java entre los archivos SDK en mi computadora. El siguiente texto de la página vinculada parece prometedor:

 Register for getting notifications for change in the Call State Call.State This is called PreciseCallState because the call state is more precise than the Phone.State which can be obtained using the android.telephony.PhoneStateListener Resulting events will have an AsyncResult in Message.obj. AsyncResult.userData will be set to the obj argument here. The h parameter is held only by a weak reference. 1051 1052 public void registerForPreciseCallStateChanged(Handler h, int what, Object obj){ 1053 mPreciseCallStateRegistrants.addUnique(h, what, obj); 1054 } 

No he intentado codificar nada, así que realmente no sé si puede hacer lo que quieres, pero tengo curiosidad por saberlo.

Por favor, preste atención a:

 tm.listen(new PhoneStateListener() { @Override public void onCallStateChanged(int state, String incomingNumber) { switch (state) { case TelephonyManager.CALL_STATE_RINGING: Log.d(This.LOG_TAG, "RINGING"); break; case TelephonyManager.CALL_STATE_OFFHOOK: Log.d(This.LOG_TAG, "OFFHOOK"); break; case TelephonyManager.CALL_STATE_IDLE: Log.d(This.LOG_TAG, "IDLE"); break; default: Log.d(This.LOG_TAG, "Default: " + state); break; } } }, PhoneStateListener.LISTEN_CALL_STATE); 

¿Ves el argumento “incomingNumber”? Sí, ese código solo puede detectar su estado de llamada telefónica cuando hay una llamada entrante a su dispositivo.

Podrías hacer lo siguiente … no muy preciso, pero podría hacer el truco:

  1. Utiliza el receptor para la acción android.intent.action.NEW_OUTGOING_CALL
  2. Cuando se llama al receptor, almacena en alguna parte (por ejemplo, una var estática) el estado NEW_OUTGOIN_CALL y el tiempo en ms cuando esto sucedió (es decir, nueva Fecha (). GetTime ())
  3. Utiliza el otro receptor para android.intent.action.PHONE_STATE y en el mensaje onReceive haz lo siguiente:

     if (intent.getAction().equals("android.intent.action.PHONE_STATE")) { TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); telephony.listen(new PhoneStateListener() { public void onCallStateChanged(int state, String incomingNumber) { switch(state) { case TelephonyManager.CALL_STATE_IDLE: break; case TelephonyManager.CALL_STATE_OFFHOOK: break; case TelephonyManager.CALL_STATE_RINGING: break; } } }, PhoneStateListener.LISTEN_CALL_STATE); } 

En el caso CALL_STATE_OFFHOOK, comprueba que el último estado almacenado fue NEW_OUTGOING_CALL y que no más de aprox. Han pasado 10 segundos desde el último cambio de estado. Esto significa que el teléfono inició una llamada hace como máximo 10 segundos y que ahora está en estado de descolgado (es decir, llamada activa) sin pasar por inactivo o sonando. Esto podría significar que la llamada fue respondida.

Aquí su respuesta es que ha implementado CallStateListener en OutGoingCallReceiver que es incorrecto. Tienes que implementar CallStateListener en PhoneStateListener

También probé esto en mi proyecto anterior, me enfrenté al mismo problema y luego lo resolví como a continuación. Tomé 3 clases como a continuación.

  1. AutoCallReceiver: Registre el TelephonyManager con PhoneStateListener.LISTEN_CALL_STATE

  2. CallStateListener que escucha tres estados como TelephonyManager.CALL_STATE_IDLE , TelephonyManager.CALL_STATE_OFFHOOK , TelephonyManager.CALL_STATE_RINGING

3.OutGoingCallReceiver que se encarga de la llamada en curso

 public class OutGoingCallReceiver extends BroadcastReceiver { /* onReceive will execute on out going call */ @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "OutGoingCallReceiver", Toast.LENGTH_SHORT).show(); } } 

 public class CallStateListener extends PhoneStateListener { String number=""; // variable for storing incoming/outgoing number Context mContext; // Application Context //Constructor that will accept Application context as argument public CallStateListener(Context context) { mContext=context; } // This function will automatically invoke when call state changed public void onCallStateChanged(int state,String incomingNumber) { boolean end_call_state=false; // this variable when true indicate that call is disconnected switch(state) { case TelephonyManager.CALL_STATE_IDLE: // Handling Call disconnect state after incoming/outgoing call Toast.makeText(mContext, "idle", Toast.LENGTH_SHORT).show(); break; case TelephonyManager.CALL_STATE_OFFHOOK: // Handling outgoing call Toast.makeText(mContext, "OFFHOOK", Toast.LENGTH_SHORT).show(); // saving outgoing call state so that after disconnect idle state can act accordingly break; case TelephonyManager.CALL_STATE_RINGING: Toast.makeText(mContext, "RINGING", Toast.LENGTH_SHORT).show(); break; } } } 

 public class AutoCallReceiver extends BroadcastReceiver { /* onReceive will execute on call state change */ @Override public void onReceive(Context context, Intent intent) { // Instantiating PhoneStateListener CallStateListener phoneListener=new CallStateListener(context); // Instantiating TelephonyManager TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); // Registering the telephony to listen CALL STATE change telephony.listen(phoneListener,PhoneStateListener.LISTEN_CALL_STATE); } 

}