Comment raccrocher appel sortant sur Android?
je développe une application où l'une des choses dont nous avons besoin est de contrôler l'appel sortant, au moins pour pouvoir l'arrêter de notre application.
j'ai essayé d'utiliser Intent.ACTION_CALL
d'une activité existante:
Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phoneNumber));
startActivity(callIntent);
mais arrêter l'appel semble être interdit par L'API.
pouvez-vous suggérer une solution?
par exemple: activer le mode avion pendant l'appel? Juste un exemple: ce piratage n'a pas marché pour moi.
8 réponses
capturer l'appel sortant dans un BroadcastReceiver
a été mentionné et est certainement la meilleure façon de le faire si vous voulez mettre fin à l'appel avant de composer.
une fois que la composition ou l'appel, cependant, cette technique ne fonctionne plus. La seule façon de raccrocher que j'ai rencontré jusqu'à présent, est de le faire à travers Java Reflection . Comme il ne fait pas partie de l'API publique, vous devez faire attention à l'utiliser, et ne pas compter sur elle . Tout modifier la composition interne D'Android va effectivement briser votre application.
le blog de Prasanta Paul démontre comment cela peut être accompli, ce que j'ai résumé ci-dessous.
obtenir le ITelephony
objet:
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);
}
fin de l'appel:
telephonyService.endCall();
essayez ceci:
(j'ai utilisé réflexion pour accéder aux fonctions de téléphonie avancées et modifier quelque chose)
// 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);
}
- créer un
BroadcastReceiver
avec une priorité de 0. - En la colombie-britannique intercepter le
ACTION_NEW_OUTGOING_CALL
l'intention de sononReceive
méthode - appel
setResultData(null)
dans la même méthode
Cela permettra d'éviter l'appel, de l'ouverture (tant que votre récepteur est le dernier processus de l'intention, je pense)
vous pouvez essayer d'activer puis désactiver le mode avion:
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);
Pour 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);
}
}
}
}
en outre dans le Manifeste mis dans la section d'emballage:
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
C'est tout.
considérant le potentiel de merveilleux méfaits, je serais surpris si cela était permis.
ce fil indique clairement que L'API ne peut pas terminer un appel . D'autres ont essayé .
voici le code le plus mis à jour, qui fonctionnera pour Android P too, car il a une API officielle pour lui ( ici ) :
dans le manifeste, ajouter ceci:
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS"/>
en code, utilisez ceci:
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://stackoverflow.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;
}
ou à 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://stackoverflow.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
}
}
selon la documentation sur ACTION_NEW_OUTGOING_CALL
L'Intention de la valeur supplémentaire:EXTRA_PHONE_NUMBER-le numéro de téléphone initialement prévu pour être composé.
une fois l'émission terminée, les données de résultat sont utilisées comme nombre réel à appeler. Si null, aucun appel ne sera passé.