llamada - permission call phone android
Cómo detectar cuando el teléfono es respondido o rechazado (4)
La respuesta anterior es completamente incorrecta en el caso de llamadas salientes. En Android no hay manera de que uno pueda detectar si la llamada fue realmente respondida (en el caso de llamadas salientes). En el momento en que marca un número, se off_hook
estado off_hook
. Este es uno de los inconvenientes de la programación de Android.
Logré preparar una actividad cuando el teléfono está sonando. Ahora necesito saber cómo cancelar esta actividad cuando responda el teléfono o rechazo la llamada. ¿Llamo a EXTRA_STATE_IDLE? EXTRA_STATE_OFFHOOK?
¿Algunas ideas?
<receiver android:name=".IncomingBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE"/>
</intent-filter>
</receiver>
public class IncomingBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
// If an incoming call arrives
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING))
{ //Did my work }
Los siguientes son los estados que atraviesa en diferentes escenarios:
1) Contestar la llamada recibida
CALL_STATE_RINGING => CALL_STATE_OFFHOOK (After Answering call) => CALL_STATE_IDLE (After End call)
2) Rechazar / No contestar (Perdido) Llamada recibida
CALL_STATE_RINGING => CALL_STATE_IDLE (After End call)
3) Llamada de marcado
CALL_STATE_OFFHOOK (After dialing) => CALL_STATE_IDLE (After End call)
Código
int prev_state=0;
public class CustomPhoneStateListener extends PhoneStateListener {
private static final String TAG = "CustomPhoneStateListener";
@Override
public void onCallStateChanged(int state, String incomingNumber){
if(incomingNumber!=null&&incomingNumber.length()>0) incoming_nr=incomingNumber;
switch(state){
case TelephonyManager.CALL_STATE_RINGING:
Log.d(TAG, "CALL_STATE_RINGING");
prev_state=state;
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.d(TAG, "CALL_STATE_OFFHOOK");
prev_state=state;
break;
case TelephonyManager.CALL_STATE_IDLE:
Log.d(TAG, "CALL_STATE_IDLE==>"+incoming_nr);
NumberDatabase database=new NumberDatabase(mContext);
if((prev_state==TelephonyManager.CALL_STATE_OFFHOOK)){
prev_state=state;
//Answered Call which is ended
}
if((prev_state==TelephonyManager.CALL_STATE_RINGING)){
prev_state=state;
//Rejected or Missed call
}
break;
}
}
}
En tu receptor
onReceive(Context context, Intent intent) {
TelephonyManager telephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); //TelephonyManager object
CustomPhoneStateListener customPhoneListener = new CustomPhoneStateListener();
telephony.listen(customPhoneListener, PhoneStateListener.LISTEN_CALL_STATE); //Register our listener with TelephonyManager
Bundle bundle = intent.getExtras();
String phoneNr= bundle.getString("incoming_number");
mContext=context;
}
a continuación se muestra un código de detección de llamadas salientes por eventos de accesibilidad:
Agregue una clase que amplíe AccessibilityService
en sus proyectos:
public class CallDetection extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
acquireLock(this);
Log.d("myaccess","after lock");
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {
Log.d("myaccess","in window changed");
AccessibilityNodeInfo info = event.getSource();
if (info != null && info.getText() != null) {
String duration = info.getText().toString();
String zeroSeconds = String.format("%02d:%02d", new Object[]{Integer.valueOf(0), Integer.valueOf(0)});
String firstSecond = String.format("%02d:%02d", new Object[]{Integer.valueOf(0), Integer.valueOf(1)});
Log.d("myaccess","after calculation - "+ zeroSeconds + " --- "+ firstSecond + " --- " + duration);
if (zeroSeconds.equals(duration) || firstSecond.equals(duration)) {
Toast.makeText(getApplicationContext(),"Call answered",Toast.LENGTH_SHORT).show();
// Your Code goes here
}
info.recycle();
}
}
}
@Override
protected void onServiceConnected() {
super.onServiceConnected();
Toast.makeText(this,"Service connected",Toast.LENGTH_SHORT).show();
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
info.eventTypes = AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
info.notificationTimeout = 0;
info.packageNames = null;
setServiceInfo(info);
}
@Override
public void onInterrupt() {
}
}
Pero para que la función event.getSource()
funcione, debe especificar parte de la configuración del servicio a través de xml, por lo tanto, cree una carpeta xml en su proyecto y agregue un archivo xml llamado serviceconfig.xml (puede dar el nombre que desee).
El contenido de serviceconfig está debajo -
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/callDetection"
android:accessibilityEventTypes="typeWindowContentChanged"
android:notificationTimeout="100"
android:canRetrieveWindowContent="true"
/>
Puede encontrar más información sobre serviceconfig en Here
Ahora agregue su servicio en su archivo Manifiesto como este -
<service android:name=".CallDetection"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:label="@string/callDetection">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/serviceconfig" />
</service>
Y listo, simplemente ejecute la aplicación y vaya a Configuración de accesibilidad en su teléfono, encontrará una opción llamada detección ( o el nombre que haya dado como descripción del servicio ), actívela para otorgar permisos de accesibilidad para su aplicación.
Ahora verá un brindis cuando se responda la llamada.
puede codificar cualquier código que desee allí, también puede llamar a una función de devolución de llamada en su actividad
Lo más importante : no llame a su ventana de llamada (ventana del marcador de Android) hasta que se responda la llamada; de lo contrario, esto no funcionará.
Nota : como Android no proporciona ninguna solución para detectar si la llamada se responde o no, esta es la mejor alternativa que he hecho, espero que funcione para usted.
en su onReceive:
PhoneStateChangeListener pscl = new PhoneStateChangeListener;
TelephonyManager tm = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(pscl, PhoneStateListener.LISTEN_CALL_STATE);
clase separada:
private class PhoneStateChangeListener extends PhoneStateListener {
public static boolean wasRinging;
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch(state){
case TelephonyManager.CALL_STATE_RINGING:
Log.i(LOG_TAG, "RINGING");
wasRinging = true;
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.i(LOG_TAG, "OFFHOOK");
if (!wasRinging) {
// Start your new activity
} else {
// Cancel your old activity
}
// this should be the last piece of code before the break
wasRinging = true;
break;
case TelephonyManager.CALL_STATE_IDLE:
Log.i(LOG_TAG, "IDLE");
// this should be the last piece of code before the break
wasRinging = false;
break;
}
}
}
Todo lo que necesita hacer es escribir un código para verificar si el estado anterior fue ''sonando''. Si el estado actual está inactivo y el estado anterior estaba sonando, cancelaron la llamada. Si el estado actual es "offhook" y el estado anterior estaba sonando, respondieron la llamada.