samsung - Cómo colgar la llamada saliente en Android?
manual de programacion android pdf (8)
- Crea un
BroadcastReceiver
con una prioridad de 0. - En BC intercepta el intento
ACTION_NEW_OUTGOING_CALL
en su métodoonReceive
- llamar a
setResultData(null)
en el mismo método
Esto evitará que la llamada se inicie (siempre que tu receptor sea el último en procesar la intención, creo)
Estoy desarrollando una aplicación donde una de las cosas que necesitamos es controlar la llamada saliente, al menos para poder detenerla desde nuestra aplicación.
Intenté usar Intent.ACTION_CALL
de una actividad existente:
Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phoneNumber));
startActivity(callIntent);
Pero detener la llamada parece no ser permitido a través de la API.
¿Puedes sugerir alguna solución?
Por ejemplo: ¿habilitar el modo avión durante la llamada? Solo un ejemplo; este truco no funcionó para mí.
Aquí está el código más actualizado, que también funcionará para Android P, porque tiene una API oficial para él (aquí):
en manifiesto, agrega esto:
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS"/>
En código, usa esto:
Java:
@SuppressLint("PrivateApi")
public static boolean endCall(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
final TelecomManager telecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
if (telecomManager != null && ContextCompat.checkSelfPermission(context, Manifest.permission.ANSWER_PHONE_CALLS) == PackageManager.PERMISSION_GRANTED) {
telecomManager.endCall();
return true;
}
return false;
}
//use unofficial API for older Android versions, as written here: https://.com/a/8380418/878126
try {
final Class<?> telephonyClass = Class.forName("com.android.internal.telephony.ITelephony");
final Class<?> telephonyStubClass = telephonyClass.getClasses()[0];
final Class<?> serviceManagerClass = Class.forName("android.os.ServiceManager");
final Class<?> serviceManagerNativeClass = Class.forName("android.os.ServiceManagerNative");
final Method getService = serviceManagerClass.getMethod("getService", String.class);
final Method tempInterfaceMethod = serviceManagerNativeClass.getMethod("asInterface", IBinder.class);
final Binder tmpBinder = new Binder();
tmpBinder.attachInterface(null, "fake");
final Object serviceManagerObject = tempInterfaceMethod.invoke(null, tmpBinder);
final IBinder retbinder = (IBinder) getService.invoke(serviceManagerObject, "phone");
final Method serviceMethod = telephonyStubClass.getMethod("asInterface", IBinder.class);
final Object telephonyObject = serviceMethod.invoke(null, retbinder);
final Method telephonyEndCall = telephonyClass.getMethod("endCall");
telephonyEndCall.invoke(telephonyObject);
return true;
} catch (Exception e) {
e.printStackTrace();
LogManager.e(e);
}
return false;
}
o en Kotlin:
@SuppressLint("PrivateApi")
fun endCall(context: Context): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val telecomManager = context.getSystemService(Context.TELECOM_SERVICE) as TelecomManager
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ANSWER_PHONE_CALLS) == PackageManager.PERMISSION_GRANTED) {
telecomManager.endCall()
return true
}
return false
}
//use unofficial API for older Android versions, as written here: https://.com/a/8380418/878126
try {
val telephonyClass = Class.forName("com.android.internal.telephony.ITelephony")
val telephonyStubClass = telephonyClass.classes[0]
val serviceManagerClass = Class.forName("android.os.ServiceManager")
val serviceManagerNativeClass = Class.forName("android.os.ServiceManagerNative")
val getService = serviceManagerClass.getMethod("getService", String::class.java)
val tempInterfaceMethod = serviceManagerNativeClass.getMethod("asInterface", IBinder::class.java)
val tmpBinder = Binder()
tmpBinder.attachInterface(null, "fake")
val serviceManagerObject = tempInterfaceMethod.invoke(null, tmpBinder)
val retbinder = getService.invoke(serviceManagerObject, "phone") as IBinder
val serviceMethod = telephonyStubClass.getMethod("asInterface", IBinder::class.java)
val telephonyObject = serviceMethod.invoke(null, retbinder)
val telephonyEndCall = telephonyClass.getMethod("endCall")
telephonyEndCall.invoke(telephonyObject)
return true
} catch (e: Exception) {
e.printStackTrace()
return false
}
}
Considerando el potencial de travesuras maravillosas, me sorprendería si esto está permitido.
Este hilo dice rotundamente que la API no puede finalizar una llamada . Otros lo han intentado .
De acuerdo con la documentación sobre ACTION_NEW_OUTGOING_CALL
La intención tendrá el siguiente valor adicional:EXTRA_PHONE_NUMBER: el número de teléfono originalmente destinado a marcarse.
Una vez que finaliza la transmisión, resultData se usa como el número real para llamar. Si es nulo, no se realizará ninguna llamada.
Para Ilana:
public class ilanasReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
if (getResultData()!=null) {
String number = "123456";
setResultData(number);
}
}
}
}
Además en Manifest poner en la sección del paquete:
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
Eso es todo.
Prueba esto:
(Utilicé Reflection para acceder a funciones avanzadas de telefonía y modificar algunas)
// required permission <uses-permission android:name="android.permission.CALL_PHONE"/>
try {
//String serviceManagerName = "android.os.IServiceManager";
String serviceManagerName = "android.os.ServiceManager";
String serviceManagerNativeName = "android.os.ServiceManagerNative";
String telephonyName = "com.android.internal.telephony.ITelephony";
Class telephonyClass;
Class telephonyStubClass;
Class serviceManagerClass;
Class serviceManagerStubClass;
Class serviceManagerNativeClass;
Class serviceManagerNativeStubClass;
Method telephonyCall;
Method telephonyEndCall;
Method telephonyAnswerCall;
Method getDefault;
Method[] temps;
Constructor[] serviceManagerConstructor;
// Method getService;
Object telephonyObject;
Object serviceManagerObject;
telephonyClass = Class.forName(telephonyName);
telephonyStubClass = telephonyClass.getClasses()[0];
serviceManagerClass = Class.forName(serviceManagerName);
serviceManagerNativeClass = Class.forName(serviceManagerNativeName);
Method getService = // getDefaults[29];
serviceManagerClass.getMethod("getService", String.class);
Method tempInterfaceMethod = serviceManagerNativeClass.getMethod(
"asInterface", IBinder.class);
Binder tmpBinder = new Binder();
tmpBinder.attachInterface(null, "fake");
serviceManagerObject = tempInterfaceMethod.invoke(null, tmpBinder);
IBinder retbinder = (IBinder) getService.invoke(serviceManagerObject, "phone");
Method serviceMethod = telephonyStubClass.getMethod("asInterface", IBinder.class);
telephonyObject = serviceMethod.invoke(null, retbinder);
//telephonyCall = telephonyClass.getMethod("call", String.class);
telephonyEndCall = telephonyClass.getMethod("endCall");
//telephonyAnswerCall = telephonyClass.getMethod("answerRingingCall");
telephonyEndCall.invoke(telephonyObject);
} catch (Exception e) {
e.printStackTrace();
Log.error(DialerActivity.this,
"FATAL ERROR: could not connect to telephony subsystem");
Log.error(DialerActivity.this, "Exception object: " + e);
}
Puede intentar habilitar y luego desactivar el modo avión:
android.provider.Settings.System.putInt(getContentResolver(),
android.provider.Settings.System.AIRPLANE_MODE_ON, 1);
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", 1);
sendBroadcast(new Intent("android.intent.action.AIRPLANE_MODE"));
sendBroadcast(intent);
android.provider.Settings.System.putInt(getContentResolver(),
android.provider.Settings.System.AIRPLANE_MODE_ON, 0);
intent.putExtra("state", 0);
sendBroadcast(new Intent("android.intent.action.AIRPLANE_MODE"));
sendBroadcast(intent);
Se mencionó la captura de la llamada saliente en un BroadcastReceiver
y es definitivamente la mejor manera de hacerlo si desea finalizar la llamada antes de marcar.
Sin embargo, una vez que marca o in-call, esa técnica ya no funciona. La única manera de colgar que he encontrado hasta ahora es hacerlo a través de Java Reflection . Como no forma parte de la API pública, debe tener cuidado de usarla y no confiar en ella . Cualquier cambio en la composición interna de Android romperá efectivamente su aplicación.
El blog de Prasanta Paul demuestra cómo se puede lograr, que he resumido a continuación.
Obtener el objeto ITelephony
:
TelephonyManager tm = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
try {
// Java reflection to gain access to TelephonyManager''s
// ITelephony getter
Log.v(TAG, "Get getTeleService...");
Class c = Class.forName(tm.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
com.android.internal.telephony.ITelephony telephonyService =
(ITelephony) m.invoke(tm);
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG,
"FATAL ERROR: could not connect to telephony subsystem");
Log.e(TAG, "Exception object: " + e);
}
Finalizando la llamada:
telephonyService.endCall();