9 votes

Quelle est la bonne façon de gérer l'action NEW_OUTGOING_CALL lors d'une boucle ?

Je développe actuellement une application qui capture l'action NEW_OUTGOING_CALL avec l'aide d'un BroadcastReceiver . J'interromps l'appel en appelant setResultData(null) . Ensuite, je montre à l'utilisateur un dialogue qui lui permet de décider s'il veut utiliser mon application pour réécrire son numéro. Lorsque l'utilisateur a pris sa décision, je passe le nouvel appel en fonction de sa décision. Mon récepteur de radiodiffusion est à nouveau appelé.

Quelle est la bonne façon de savoir si j'ai déjà traité le numéro ? J'ai trouvé une solution qui utilise l'horodatage pour deviner si le numéro a déjà été traité. Une autre solution serait d'ajouter un "+" à la fin du numéro traité. Ces méthodes fonctionnent bien pour mon application, qui est la seule à attraper le NEW_OUTGOING_CALL événement. Mais que dois-je faire lorsque d'autres applications (comme Sipdroid ou Google Voice) sont également présentes et capturent l'événement. NEW_OUTGOING_CALL de l'interrompre et de le redémarrer ? Je ne vois pas de possibilité de savoir si nous sommes toujours dans le même "flux d'appels" et si j'ai déjà traité le numéro.

J'aimerais connaître vos idées sur ce problème !

2voto

Scot Points 78

Avec quel niveau d'API travaillez-vous ? S'il est >= 11, consultez la nouvelle fonction BroadcastReceiver.goAsync qui vous permet d'étendre le traitement de la diffusion en dehors de la fonction onReceive de votre récepteur. Cela pourrait vous éviter d'avoir à faire une boucle.

Si, comme moi, vous êtes coincé avant le niveau 11, sachez qu'il est étonnamment difficile d'y parvenir de manière élégante. Vous l'avez peut-être déjà fait, mais j'ai essayé d'inclure un drapeau "processed" dans l'intention ACTION_CALL générée par mon code, en espérant qu'il serait inclus dans l'émission ACTION_NEW_OUTGOING_CALL qui en résulterait, mais cela ne fonctionne malheureusement pas.

La meilleure solution que j'ai trouvée consiste à inclure un fragment dans l'URI de l'intention ACTION_CALL que vous générez. Ce fragment sera inclus dans l'émission ACTION_NEW_OUTGOING_CALL qui en résulte, de sorte que le récepteur de l'émission puisse faire la différence entre l'appel original et celui que vous générez, mais il n'interférera pas avec les gestionnaires qui ne le recherchent pas.

Voici le code de base.

Dans votre BroadcastReceiver pour l'ACTION_NEW_OUTGOING_CALL

public class YourBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // extract the fragment from the URI
        String uriFragment = Uri.parse(
            intent.getStringExtra("android.phone.extra.ORIGINAL_URI")).getFragment();

        // if the fragment is missing or does not have your flag, it is new
        if (uriFragment == null || !uriFragment.contains("your_flag")) {

            // launch your activity, pass the phone number, etc.
            // use getResultData to get the number in order to respect
            // earlier broadcast receivers
            ...

            // abort the broadcast
            this.setResultData(null);
            this.abortBroadcast();
        }
        // otherwise, your code is there, this call was triggered by you
        else {
            // unless you have a special need, you'll probably just let the broadcast
            // go through here

            // note that resultData ignores the fragment, so other receivers should
            // be blissfully unaware of it
        }
    }
}

Lorsque l'utilisateur compose le numéro pour la première fois, soit le fragment n'est pas présent, soit votre drapeau n'est pas présent, ce qui vous permet d'interrompre la diffusion et de commencer votre activité. Dans votre activité, si vous décidez de passer à nouveau l'appel, faites quelque chose comme ce qui suit :

startActivity(new Intent(Intent.ACTION_CALL,
                         Uri.parse("tel:" + modified_number + "#your_flag")));

Le fragment "your_flag" sera alors présent dans l'émission NEW_OUTGOING_CALL suivante et vous permettra ainsi de traiter ce cas différemment dans votre récepteur d'émission.

Ce qui est bien, c'est que le fragment est complètement ignoré à moins que vous ne le recherchiez dans l'ORIGINAL_URI, de sorte que d'autres récepteurs de diffusion peuvent continuer à fonctionner. Si vous voulez être vraiment gentil, vous pouvez rechercher un fragment existant et y ajouter votre drapeau (éventuellement avec une virgule de séparation).

J'espère que cela vous aidera. Je vous souhaite bonne chance !

1voto

Samuel Tardieu Points 1551

Je ne vois pas de possibilité d'arriver à si nous sommes toujours dans le même "appel". et si j'ai déjà traité le numéro.

Techniquement, vous n'êtes pas dans le même "flux d'appels" car le placement d'un nouvel appel est asynchrone. Vous devez utiliser des indices (tels qu'un horodatage) comme vous semblez le faire déjà.

Si vous êtes certain que d'autres applications ne réécriront pas le numéro, sauf pour modifier le préfixe ou ajouter un suffixe, vous pouvez ajouter un autre indice de "contrôle de proximité" pour éviter les faux positifs/négatifs, mais je crains que ce soit tout ce que vous pouvez faire.

0voto

Vaibhav Points 11

La méthode onReceive() du récepteur de diffusion reçoit une intention comme argument. Extrayez l'offre groupée de l'intention à l'aide de Intent.getExtras(). Cet ensemble contient 3 paires clé-valeur comme suit :

  1. Android.phone.extra.ALREADY_CALLED = null
  2. Android.intent.extra.PHONE_NUMBER = 98xxxxxx98
  3. Android.phone.extra.ORIGINAL_URI = tel : 98xxxxxx98

98xxxxxx98 est le numéro composé par l'utilisateur.

Lorsque la fonction onReceive() est appelée à nouveau, ce numéro devient 98xxxxxx98* o 0* En vérifiant la présence de l'astérisque (*) à la fin du numéro composé, il est possible de déterminer si la méthode onReceive() est appelée pour la première fois ou les fois suivantes.

0voto

ZeC Points 716

L'une des réponses serait de suivre l'extra booléen dans l'intention. L'application Google Phone procède de la même manière. Vous pouvez consulter ce BroadcastReceiver ici (rechercher l'utilisation de alreadyCalled)

L'autre façon serait de passer ce numéro "réécrit" de votre diffusion au récepteur de diffusion suivant (qui peut être n'importe quelle application, comme Sipdroid, Google Voice, ou une application VoIP personnalisée) sans appeler l'intention ACTION_CALL (c'est pourquoi vous obtenez une boucle et que votre récepteur de diffusion est appelé à nouveau) Le code suivant est un exemple de la façon dont je gère les appels dans mon application VoIP personnalisée. Lorsque j'intercepte NEW_OUTGOING_CALL dans mon récepteur de diffusion, je vérifie d'abord s'il y a une connexion internet. Si le téléphone est connecté à Internet, j'utilise l'action custom defined intent de mon activité pour passer l'appel via mon application VoIP. S'il n'y a pas de connexion internet, je mets simplement le numéro de téléphone original dans les données de résultat du récepteur de diffusion. Ce numéro est utilisé par le prochain récepteur de diffusion (probablement l'application téléphonique par défaut, mais ce n'est pas obligatoire) dans le flux pour passer un appel.

public class BHTTalkerCallReceiver extends BroadcastReceiver {

    private static final String TAG = "BHTTalkerCallReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {

        Log.d(TAG, "Broadcast successfull ... ");

        // Extract phone number reformatted by previous receivers
        String phoneNumber = getResultData();
        if (phoneNumber == null) {
            // No reformatted number, use the original
            phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
        }

        if (isNetworkAvailable(context)) { // Make sure this app handles call only if there is internet connection
            // My app will bring up the call, so cancel the broadcast
            setResultData(null);
            // Start my app to bring up the call
            Intent voipCallIntent = new Intent(context, TalkerActivity.class);
            voipCallIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            voipCallIntent.putExtra(TalkerActivity.OUT_CALL_NUMBER, phoneNumber);
            voipCallIntent.setAction(TalkerActivity.BHT_TALKER_OUT_CALL);
            context.startActivity(voipCallIntent);
        } else { //otherwise make a regular call...
            // Forward phone data to standard phone call
            setResultData(phoneNumber);
        }
    }

    private boolean isNetworkAvailable(final Context context) {
        final ConnectivityManager connectivityManager = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
        return connectivityManager.getActiveNetworkInfo() != null && connectivityManager.getActiveNetworkInfo().isConnected();
    }
}

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