48 votes

Comment raccrocher un appel sortant sur Android ?

Je suis en train de développer une application où l'une des choses dont nous avons besoin est de contrôler l'appel sortant, au moins être capable de l'arrêter depuis notre application.

J'ai essayé d'utiliser Intent.ACTION_CALL à partir d'une activité existante :

Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + numéro de téléphone)); 
startActivity(callIntent); 

Mais il semble que l'arrêt de l'appel soit interdit via l'API.

Pouvez-vous suggérer une solution de contournement ?

Par exemple : activer le mode avion pendant l'appel ? Juste un exemple; cette astuce n'a pas fonctionné pour moi.

0 votes

Terminer l'appel est possible. TextMe4Callback sur le marché Android le fait.

0 votes

Avez-vous réussi à utiliser BroadcastReceiver? Pourriez-vous revoir cette question et/ou accepter une réponse ?

31voto

Paul Lammertsma Points 12817

Capturer l'appel sortant dans un BroadcastReceiver a été mentionné et est certainement le meilleur moyen de le faire si vous voulez mettre fin à l'appel avant de composer.

Cependant, une fois l'appel composé ou en cours, cette technique ne fonctionne plus. La seule façon que j'ai rencontrée pour raccrocher jusqu'à présent, est de le faire via Reflection Java. Comme cela ne fait pas partie de l'API publique, vous devez être prudent en l'utilisant et ne pas vous y fier. Tout changement dans la composition interne d'Android cassera efficacement votre application.

Le blog de Prasanta Paul dé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 {
    // Réflexion Java pour accéder à la méthode getITelephony de TelephonyManager
    Log.v(TAG, "Obtenir 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,
            "ERREUR FATALE: impossible de se connecter au sous-système téléphonique");
    Log.e(TAG, "Objet d'exception: " + e);
}

Fin de l'appel:

telephonyService.endCall();

6 votes

+1 Ce n'est pas une bonne pratique à faire, mais l'OP demande spécifiquement une solution de contournement pour quelque chose qui n'est pas autorisé par l'API, donc c'est une bonne réponse.

1 votes

Si c'est la seule solution, alors je pense que c'est une excellente réponse!

0 votes

Salut, je ne suis pas capable de bloquer un appel particulier avec ce code que j'ai vérifié.

28voto

EDIT: Pour Android P ou ultérieur, veuillez consulter : https://stackoverflow.com/a/51121175/450148

Essayez ceci :

(J'ai utilisé Réflexion pour accéder à des fonctionnalités téléphoniques avancées et modifier quelques choses)

// autorisation requise 

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;

    // Méthode 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,
                "ERREUR FATALE : impossible de se connecter au sous-système téléphonique");
    Log.error(DialerActivity.this, "Objet d'exception : " + e);
}

1 votes

Merci, cela fonctionne très bien pour raccrocher un appel téléphonique à travers une application.

4 votes

Fonctionne excellent. [ autorisation requise "" ]

0 votes

Fonctionne très bien. Connaissez-vous d'autres actions d'appel utiles, comme activer le haut-parleur, répondre, ... ?

21voto

  1. Créez un BroadcastReceiver avec une priorité de 0.
  2. Dans le BC interceptez l'intent ACTION_NEW_OUTGOING_CALL dans sa méthode onReceive
  3. appelez setResultData(null) dans la même méthode

Cela empêchera l'appel d'être initié (tant que votre récepteur est le dernier à traiter l'intent je pense)

9voto

android developer Points 20939

Voici le code le plus récent, qui fonctionnera également pour Android P, car il dispose d'une API officielle pour cela ([ici](https://developer.android.com/reference/android/telecom/TelecomManager.html#endCall())) :

ajoutez ceci dans le manifeste :

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;
    }
    //utilisez une API non officielle pour les anciennes versions d'Android, comme expliqué ici : 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 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
    }
    //utilisez une API non officielle pour les anciennes versions d'Android, comme expliqué ici : 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
    }
}

5voto

Gung Shi Jie Points 81

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);

4 votes

À ce stade, il n'y a aucun moyen de raccrocher un appel sortant, en soi, la solution proposée par Gung Shi Jie est une bonne idée, mais ne fonctionne pas, les changements en mode avion seront ignorés lors d'un appel sortant, cela fonctionne uniquement sur les terminaux émulés pendant le développement, j'ai essayé en vain sur les téléphones HTC Desire et Acer Liquid.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X