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 l'arrêt de l'appel semble être interdit via l'API.
Pouvez-vous suggérer une solution?
Par exemple: activer le mode avion pendant l'appel? Juste un exemple; ce hack n'a pas fonctionné pour moi.
La capture de l'appel sortant dans un BroadcastReceiver
a été mentionnée et est certainement la meilleure façon de le faire si vous souhaitez mettre fin à l'appel avant de composer.
Cependant, une fois la numérotation ou l'appel effectué, cette technique ne fonctionne plus. Le seul moyen de raccrocher que j'ai rencontré jusqu'à présent est de le faire via Java Reflection . Comme il ne fait pas partie de l'API publique, vous devriez veillez à l'utiliser, et ne vous fiez pas à lui . Toute modification de la composition interne de Android interrompt effectivement ton application.
Le blog de Prasanta Paul montre comment cela peut être accompli, que j'ai résumé ci-dessous.
Obtention de l'objet 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);
}
Fin de l'appel:
telephonyService.endCall();
Essaye ça:
(J'ai utilisé Réflexion pour accéder aux fonctionnalités avancées de téléphonie 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);
}
BroadcastReceiver
avec une priorité de 0.ACTION_NEW_OUTGOING_CALL
Dans sa méthode onReceive
setResultData(null)
dans la même méthodeCela empêchera l'appel de commencer (tant que votre récepteur est le dernier à traiter l'intention, je pense)
Vous pouvez essayer d'activer puis de 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);
Voici le code le plus mis à jour, qui fonctionnera pour Android P aussi, car il a une API officielle pour lui ( ici ):
dans le manifeste, ajoutez ceci:
<uses-permission Android:name="Android.permission.ANSWER_PHONE_CALLS"/>
Dans le 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
}
}
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 plus dans le manifeste mis dans la section package:
<uses-permission Android:name="Android.permission.PROCESS_OUTGOING_CALLS" />
C'est tout.
Compte tenu du potentiel de méfaits merveilleux, je serais surpris si cela était autorisé.
Ce fil dit clairement que l'API ne peut pas mettre fin à un appel . Autres ont essayé .
Selon la documentation sur ACTION_NEW_OUTGOING_CALL
L'intention aura la valeur supplémentaire suivante:EXTRA_PHONE_NUMBER - le numéro de téléphone initialement destiné à être composé.
Une fois la diffusion terminée, le resultData est utilisé comme numéro réel à appeler. S'il est nul, aucun appel ne sera passé.