salen - No se puede detectar cuando la llamada saliente se responde en Android
porque no puedo hacer llamadas a un numero en especifico (6)
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.
AutoCallReceiver: Registre el TelephonyManager con
PhoneStateListener.LISTEN_CALL_STATE
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);
}
}
<receiver android:name=".OutGoingCallReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
<receiver android:name=".AutoCallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
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:
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
Luego, un BroadcastReceiver
llamado OutCallLogger
que capta el evento NEW_OUTGOING_CALL
cada vez que se realiza una llamada saliente:
<receiver android:name=".listener.OutCallLogger">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
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í:
<uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
<receiver android:name=".listener.OutCallLogger">
<intent-filter>
<action android:name="android.intent.action.PRECISE_CALL_STATE" />
</intent-filter>
</receiver>
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 intento 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 pila de telefonía de Android?
Podrías hacer lo siguiente ... no muy preciso, pero podría hacer el truco:
- Utiliza el receptor para la acción android.intent.action.NEW_OUTGOING_CALL
- 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 ())
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.
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.
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.