Comment détecter les appels entrants, dans un appareil Android?


130

J'essaie de créer une application comme, lorsqu'un appel arrive sur le téléphone, je veux détecter le numéro. Voici ce que j'ai essayé, mais cela ne détecte pas les appels entrants.

Je veux exécuter mon MainActivityen arrière-plan, comment puis-je faire cela?

J'avais donné l'autorisation dans le manifestdossier.

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

Dois-je fournir autre chose dans le manifeste?

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_layout);
   }

   public class myPhoneStateChangeListener extends PhoneStateListener {
       @Override
       public void onCallStateChanged(int state, String incomingNumber) {
           super.onCallStateChanged(state, incomingNumber);
           if (state == TelephonyManager.CALL_STATE_RINGING) {
               String phoneNumber =   incomingNumber;
           }
       }
   }
}

que devons-nous faire pour Android P
Ahmad Arslan

Réponses:


336

Voici ce que j'utilise pour faire ceci:

Manifeste:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>

<!--This part is inside the application-->
    <receiver android:name=".CallReceiver" >
        <intent-filter>
            <action android:name="android.intent.action.PHONE_STATE" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
        </intent-filter>
    </receiver>

Mon détecteur d'appels réutilisable de base

package com.gabesechan.android.reusable.receivers;

import java.util.Date;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;

public abstract class PhonecallReceiver extends BroadcastReceiver {

    //The receiver will be recreated whenever android feels like it.  We need a static variable to remember data between instantiations

    private static int lastState = TelephonyManager.CALL_STATE_IDLE;
    private static Date callStartTime;
    private static boolean isIncoming;
    private static String savedNumber;  //because the passed incoming is only valid in ringing


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

        //We listen to two intents.  The new outgoing call only tells us of an outgoing call.  We use it to get the number.
        if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) {
            savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER");
        }
        else{
            String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
            String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
            int state = 0;
            if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)){
                state = TelephonyManager.CALL_STATE_IDLE;
            }
            else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
                state = TelephonyManager.CALL_STATE_OFFHOOK;
            }
            else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)){
                state = TelephonyManager.CALL_STATE_RINGING;
            }


            onCallStateChanged(context, state, number);
        }
    }

    //Derived classes should override these to respond to specific events of interest
    protected abstract void onIncomingCallReceived(Context ctx, String number, Date start);
    protected abstract void onIncomingCallAnswered(Context ctx, String number, Date start);
    protected abstract void onIncomingCallEnded(Context ctx, String number, Date start, Date end);

    protected abstract void onOutgoingCallStarted(Context ctx, String number, Date start);      
    protected abstract void onOutgoingCallEnded(Context ctx, String number, Date start, Date end);

    protected abstract void onMissedCall(Context ctx, String number, Date start);

    //Deals with actual events

    //Incoming call-  goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up
    //Outgoing call-  goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up
    public void onCallStateChanged(Context context, int state, String number) {
        if(lastState == state){
            //No change, debounce extras
            return;
        }
        switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:
                isIncoming = true;
                callStartTime = new Date();
                savedNumber = number;
                onIncomingCallReceived(context, number, callStartTime);
                break;
            case TelephonyManager.CALL_STATE_OFFHOOK:
                //Transition of ringing->offhook are pickups of incoming calls.  Nothing done on them
                if(lastState != TelephonyManager.CALL_STATE_RINGING){
                    isIncoming = false;
                    callStartTime = new Date();
                    onOutgoingCallStarted(context, savedNumber, callStartTime);                     
                }
                else
                {
                    isIncoming = true;
                    callStartTime = new Date();
                    onIncomingCallAnswered(context, savedNumber, callStartTime); 
                }

                break;
            case TelephonyManager.CALL_STATE_IDLE:
                //Went to idle-  this is the end of a call.  What type depends on previous state(s)
                if(lastState == TelephonyManager.CALL_STATE_RINGING){
                    //Ring but no pickup-  a miss
                    onMissedCall(context, savedNumber, callStartTime);
                }
                else if(isIncoming){
                    onIncomingCallEnded(context, savedNumber, callStartTime, new Date());                       
                }
                else{
                    onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());                                               
                }
                break;
        }
        lastState = state;
    }
}

Ensuite, pour l'utiliser, dérivez simplement une classe et implémentez quelques fonctions simples, quels que soient les types d'appels qui vous intéressent:

public class CallReceiver extends PhonecallReceiver {

    @Override
    protected void onIncomingCallReceived(Context ctx, String number, Date start)
    {
        //
    }

    @Override
    protected void onIncomingCallAnswered(Context ctx, String number, Date start)
    {
        //
    }

    @Override
    protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end)
    {
        //
    }

    @Override
    protected void onOutgoingCallStarted(Context ctx, String number, Date start)
    {
        //
    } 

    @Override 
    protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end)
    {
        //
    }

    @Override
    protected void onMissedCall(Context ctx, String number, Date start)
    {
        //
    }

}

De plus, vous pouvez voir un article que j'ai fait sur les raisons pour lesquelles le code est comme il est sur mon blog . Lien principal: https://gist.github.com/ftvs/e61ccb039f511eb288ee

EDIT: mis à jour pour un code plus simple, car j'ai retravaillé la classe pour mon propre usage


2
Ce code n'affiche rien. Il vous appelle quand un appel sortant commence / se termine, et vous transmet le numéro, l'heure de début et l'heure de fin. En fait, l'afficher est votre travail, car je n'ai aucun moyen de savoir comment vous voulez que cela se fasse.
Gabe Sechan

3
@GabeSechan: Génial! pouvez-vous s'il vous plaît me guider pour gérer la situation d'appel en attente?
Mehul Joisar

6
Juste pour ajouter à cela, cela ne fonctionnait pas lorsque l'application n'était pas au premier plan ou en arrière-plan jusqu'à ce que je l'ajoute dans le récepteur: "android: enabled =" true "
Rajat Sharma

1
Les variables statiques resteront actives jusqu'à ce que l'application soit expulsée de la mémoire (ce qui peut être assez long, selon si les services sont en cours d'exécution et les conditions générales de la mémoire du téléphone). Mais oui, ils peuvent être perdus. Vous pouvez l'écrire sur le disque, par exemple via les préférences partagées, mais cela peut également vous amener à obtenir de faux résultats - cela vous empêcherait d'avoir vos données correctement effacées dans plusieurs cas, comme lors du redémarrage du téléphone. Pour mon cas d'utilisation, les rares données nulles et perdues étaient meilleures que les données incorrectes. N'hésitez pas à modifier cela selon vos besoins.
Gabe Sechan

1
@GabeSechan: Il semble y avoir un bug dedans. lastState ne doit pas être initialisé à CALL_STATE_IDLE. Je manque quelques appels lorsque mon application est tuée alors que l'état actuel est RINGING. Parce que quand il redevient IDLEà la fin de l'appel, la variable statique est réinitialisée CALL_STATE_IDLEet elle déborde sans rien faire. Nous perdons donc la référence à lastState.
Heisenberg

23
private MyPhoneStateListener phoneStateListener = new MyPhoneStateListener();

enregistrer

TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);

et se désinscrire

TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);

où dois-je l'utiliser dans l'activité principale?
Jesbin MJ

placez ceci dans la classe où écoutez-vous le changement .. normalement les registres sont faits dans oncreate et désinscrivez dans ondestroy .. déclarez l'objet globalement dans la classe
stinepike

Cette option ne nécessite pas d'autorisations.
Mike

alors que la solution de Gabe est mieux adaptée pour des fonctionnalités plus intrusives, c'est-à-dire le type d'application Viber, c'est la meilleure solution pour ceux qui ont besoin de réagir simplement aux actions de l'utilisateur lors d'un appel téléphonique. Demander une autorisation d'exécution dans des cas comme celui-ci est très probablement excessif et risque de ne pas être bien reçu par l'utilisateur.
bosphère

1
Je veux faire quelque chose, quand un appel arrive, comment faire avec ce code?
Noor Hossain

14

Avec Android P - Api Level 28: vous devez obtenir l'autorisation READ_CALL_LOG

Accès restreint aux journaux d'appels

Android P déplace les CALL_LOG, READ_CALL_LOG, WRITE_CALL_LOGet PROCESS_OUTGOING_CALLSautorisations du PHONEgroupe d'autorisation au nouveau CALL_LOGgroupe d'autorisation. Ce groupe offre aux utilisateurs un meilleur contrôle et une meilleure visibilité des applications qui ont besoin d'accéder à des informations sensibles sur les appels téléphoniques, telles que la lecture des enregistrements d'appels téléphoniques et l'identification des numéros de téléphone.

Pour lire les numéros de l'action d'intention PHONE_STATE, vous avez besoin à la fois de l' READ_CALL_LOGautorisation et de l' READ_PHONE_STATEautorisation . Pour lire les numéros à partir de onCallStateChanged(), vous n'avez plus besoin que de l' READ_CALL_LOGautorisation. Vous n'avez plus besoin de l' READ_PHONE_STATEautorisation.


pour ceux qui ne fait qu'ajouter READ_CALL_LOGà se AndroidManifest.xmlconcentrer sur l' ajout d' une demande d'autorisation en MainActivity.
Piyush

13

MISE À JOUR: Le code vraiment génial publié par Gabe Sechan ne fonctionne plus à moins que vous ne demandiez explicitement à l'utilisateur d'accorder les autorisations nécessaires. Voici un code que vous pouvez placer dans votre activité principale pour demander ces autorisations:

    if (getApplicationContext().checkSelfPermission(Manifest.permission.READ_PHONE_STATE)
            != PackageManager.PERMISSION_GRANTED) {
        // Permission has not been granted, therefore prompt the user to grant permission
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.READ_PHONE_STATE},
                MY_PERMISSIONS_REQUEST_READ_PHONE_STATE);
    }

    if (getApplicationContext().checkSelfPermission(Manifest.permission.PROCESS_OUTGOING_CALLS)
            != PackageManager.PERMISSION_GRANTED) {
        // Permission has not been granted, therefore prompt the user to grant permission
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.PROCESS_OUTGOING_CALLS},
                MY_PERMISSIONS_REQUEST_PROCESS_OUTGOING_CALLS);
    }

AUSSI: Comme quelqu'un l'a mentionné dans un commentaire sous la publication de Gabe , vous devez ajouter un petit extrait de code,, android:enabled="trueau récepteur afin de détecter les appels entrants lorsque l'application n'est pas actuellement en cours d'exécution au premier plan:

    <!--This part is inside the application-->
    <receiver android:name=".CallReceiver" android:enabled="true">
        <intent-filter>
            <action android:name="android.intent.action.PHONE_STATE" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
        </intent-filter>
    </receiver>

Que faire si l'application n'a aucune activité et uniquement le récepteur de diffusion et un service. Alors, où écrivons-nous ce code pour obtenir l'autorisation de l'utilisateur car le récepteur de diffusion ne sera pas appelé tant que cette autorisation ne sera pas donnée.
user2779311

2
Vous avez au moins besoin d'un MainActivity même s'il n'est ouvert qu'une seule fois. Prenez mon application de blocage d'appel RoboStop par exemple: lorsque l'utilisateur télécharge l'application pour la première fois, puis clique sur l'icône de l'application pour lancer l'application, il est alors invité à accorder à mon application les autorisations nécessaires. L'application dispose également d'un bouton pour activer / désactiver le blocage des appels, mais l'utilisateur n'a pas besoin de relancer l'application / l'activité, le blocage des appels aura lieu en arrière-plan sans que l'utilisateur n'ait à relancer l'application / l'activité.
topherPedersen

Ceux qui ont du mal à l'implémenter, suivez ce tutoriel studytutorial.in
...

5

cela peut vous aider et ajouter une autorisation requise

public class PhoneListener extends PhoneStateListener
{
    private Context context;
    public static String getincomno;

    public PhoneListener(Context c) {
        Log.i("CallRecorder", "PhoneListener constructor");
        context = c;
    }

    public void onCallStateChanged (int state, String incomingNumber)
    {

        if(!TextUtils.isEmpty(incomingNumber)){
        // here for Outgoing number make null to get incoming number
        CallBroadcastReceiver.numberToCall = null;
        getincomno = incomingNumber;
        }

        switch (state) {
        case TelephonyManager.CALL_STATE_IDLE:

            break;
        case TelephonyManager.CALL_STATE_RINGING:
            Log.d("CallRecorder", "CALL_STATE_RINGING");
            break;
        case TelephonyManager.CALL_STATE_OFFHOOK:

            break;
        }
    }
}

2
cela semble très bien. Mais comment puis-je l'utiliser à partir d'une activité? s'il vous plaît dites-moi les détails
Amir


2

Voici une méthode simple qui peut éviter l'utilisation PhonestateListeneret d'autres complications.
Nous recevons donc ici les 3 événements d'Android tels que RINGING, OFFHOOKet IDLE. Et pour obtenir le nous devons définir nos propres états comme tous les états possibles d' un appel, RINGING, OFFHOOK, IDLE, FIRST_CALL_RINGING, SECOND_CALL_RINGING. Il peut gérer tous les états d'un appel téléphonique.
Veuillez penser d'une manière que nous recevons des événements d'Android et nous définirons nos états sur appel. Voir le code.

public class CallListening  extends BroadcastReceiver {
    private static final String TAG ="broadcast_intent";
    public static String incoming_number;
    private String current_state,previus_state,event;
    public static Boolean dialog= false;
    private Context context;
    private SharedPreferences sp,sp1;
    private SharedPreferences.Editor spEditor,spEditor1;
    public void onReceive(Context context, Intent intent) {
        //Log.d("intent_log", "Intent" + intent);
        dialog=true;
        this.context = context;
        event = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
        incoming_number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
        Log.d(TAG, "The received event : "+event+", incoming_number : " + incoming_number);
        previus_state = getCallState(context);
        current_state = "IDLE";
        if(incoming_number!=null){
            updateIncomingNumber(incoming_number,context);
        }else {
            incoming_number=getIncomingNumber(context);
        }
        switch (event) {
            case "RINGING":
                Log.d(TAG, "State : Ringing, incoming_number : " + incoming_number);
            if((previus_state.equals("IDLE")) || (previus_state.equals("FIRST_CALL_RINGING"))){
                    current_state ="FIRST_CALL_RINGING";
                }
                if((previus_state.equals("OFFHOOK"))||(previus_state.equals("SECOND_CALL_RINGING"))){
                    current_state = "SECOND_CALL_RINGING";
                }

                break;
            case "OFFHOOK":
                Log.d(TAG, "State : offhook, incoming_number : " + incoming_number);
                if((previus_state.equals("IDLE")) ||(previus_state.equals("FIRST_CALL_RINGING")) || previus_state.equals("OFFHOOK")){
                    current_state = "OFFHOOK";
                }
                if(previus_state.equals("SECOND_CALL_RINGING")){
                    current_state ="OFFHOOK";
                    startDialog(context);
                }
                break;
            case "IDLE":
                Log.d(TAG, "State : idle and  incoming_number : " + incoming_number);
                if((previus_state.equals("OFFHOOK")) || (previus_state.equals("SECOND_CALL_RINGING")) || (previus_state.equals("IDLE"))){
                    current_state="IDLE";
                }
                if(previus_state.equals("FIRST_CALL_RINGING")){
                    current_state = "IDLE";
                    startDialog(context);
                }
                updateIncomingNumber("no_number",context);
                Log.d(TAG,"stored incoming number flushed");
                break;
        }
        if(!current_state.equals(previus_state)){
            Log.d(TAG, "Updating  state from "+previus_state +" to "+current_state);
            updateCallState(current_state,context);

        }
    }
    public void startDialog(Context context) {
        Log.d(TAG,"Starting Dialog box");
        Intent intent1 = new Intent(context, NotifyHangup.class);
        intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent1);

    }
    public void updateCallState(String state,Context context){
        sp = PreferenceManager.getDefaultSharedPreferences(context);
        spEditor = sp.edit();
        spEditor.putString("call_state", state);
        spEditor.commit();
        Log.d(TAG, "state updated");

    }
    public void updateIncomingNumber(String inc_num,Context context){
        sp = PreferenceManager.getDefaultSharedPreferences(context);
        spEditor = sp.edit();
        spEditor.putString("inc_num", inc_num);
        spEditor.commit();
        Log.d(TAG, "incoming number updated");
    }
    public String getCallState(Context context){
        sp1 = PreferenceManager.getDefaultSharedPreferences(context);
        String st =sp1.getString("call_state", "IDLE");
        Log.d(TAG,"get previous state as :"+st);
        return st;
    }
    public String getIncomingNumber(Context context){
        sp1 = PreferenceManager.getDefaultSharedPreferences(context);
        String st =sp1.getString("inc_num", "no_num");
        Log.d(TAG,"get incoming number as :"+st);
        return st;
    }
}

0

@Gabe Sechan, merci pour votre code. Cela fonctionne bien sauf leonOutgoingCallEnded() . Il n'est jamais exécuté. Les téléphones de test sont Samsung S5 et Trendy. Il y a 2 bugs je pense.

1: il manque une paire de crochets.

case TelephonyManager.CALL_STATE_IDLE: 
    // Went to idle-  this is the end of a call.  What type depends on previous state(s)
    if (lastState == TelephonyManager.CALL_STATE_RINGING) {
        // Ring but no pickup-  a miss
        onMissedCall(context, savedNumber, callStartTime);
    } else {
        // this one is missing
        if(isIncoming){
            onIncomingCallEnded(context, savedNumber, callStartTime, new Date());                       
        } else {
            onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());                                               
        }
    }
    // this one is missing
    break;

2: lastStaten'est pas mis à jour par le states'il est à la fin de la fonction. Il doit être remplacé à la première ligne de cette fonction par

public void onCallStateChanged(Context context, int state, String number) {
    int lastStateTemp = lastState;
    lastState = state;
    // todo replace all the "lastState" by lastStateTemp from here.
    if (lastStateTemp  == state) {
        //No change, debounce extras
        return;
    }
    //....
}

Supplémentaire j'ai mis lastStateetsavedNumber partagé les préférences comme vous l'avez suggéré.

Je viens de le tester avec les modifications ci-dessus. Bug corrigé au moins sur mes téléphones.


0

Veuillez utiliser le code ci-dessous. Cela vous aidera à obtenir le numéro entrant avec d'autres détails de l'appel.

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >

<TextView
    android:id="@+id/call"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    android:text="@string/hello_world" />

</RelativeLayout>

MainActivity.java

public class MainActivity extends Activity {

private static final int MISSED_CALL_TYPE = 0;
private TextView txtcall;

@Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    txtcall = (TextView) findViewById(R.id.call);

    StringBuffer sb = new StringBuffer();
    Cursor managedCursor = managedQuery(CallLog.Calls.CONTENT_URI, null,
            null, null, null);
    int number = managedCursor.getColumnIndex(CallLog.Calls.NUMBER);
    int type = managedCursor.getColumnIndex(CallLog.Calls.TYPE);
    int date = managedCursor.getColumnIndex(CallLog.Calls.DATE);
    int duration = managedCursor.getColumnIndex(CallLog.Calls.DURATION);
    sb.append("Call Details :");
    while (managedCursor.moveToNext()) {
        String phNumber = managedCursor.getString(number);
        String callType = managedCursor.getString(type);
        String callDate = managedCursor.getString(date);
        Date callDayTime = new Date(Long.valueOf(callDate));
        String callDuration = managedCursor.getString(duration);
        String dir = null;
        int dircode = Integer.parseInt(callType);
        switch (dircode) {

        case CallLog.Calls.OUTGOING_TYPE:
            dir = "OUTGOING";
            break;

        case CallLog.Calls.INCOMING_TYPE:
            dir = "INCOMING";
            break;

        case CallLog.Calls.MISSED_TYPE:
            dir = "MISSED";
            break;
        }
        sb.append("\nPhone Number:--- " + phNumber + " \nCall Type:--- "
                + dir + " \nCall Date:--- " + callDayTime
                + " \nCall duration in sec :--- " + callDuration);
        sb.append("\n----------------------------------");
    }
    managedCursor.close();
    txtcall.setText(sb);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}

} 

et dans votre demande manifeste pour les autorisations suivantes:

<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_LOGS"/>

READ_LOGS pour que votre application soit bannie du Play Store
Duna

0

Vous avez besoin d'un BroadcastReceiver pour ACTION_PHONE_STATE_CHANGED Cela appellera votre reçu chaque fois que l'état du téléphone change de veille, de sonnerie, de décroché, donc de la valeur précédente et de la nouvelle valeur, vous pouvez détecter s'il s'agit d'un appel entrant / sortant.

L'autorisation requise serait:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

Mais si vous souhaitez également recevoir le EXTRA_INCOMING_NUMBER dans cette diffusion, vous aurez besoin d'une autre autorisation: "android.permission.READ_CALL_LOG"

Et le code quelque chose comme ça:

val receiver: BroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d(TAG, "onReceive")
    }
}

override fun onResume() {
    val filter = IntentFilter()
    filter.addAction("android.intent.action.PHONE_STATE")
    registerReceiver(receiver, filter)
    super.onResume()
}

override fun onPause() {
    unregisterReceiver(receiver)
    super.onPause()
}

et dans la classe de récepteur, nous pouvons obtenir l'état actuel en lisant l'intention comme ceci:

intent.extras["state"]

le résultat des extras pourrait être:

SONNERIE -> Si votre téléphone sonne

OFFHOOK -> Si vous parlez avec quelqu'un (appel entrant ou sortant)

IDLE -> si l'appel est terminé (appel entrant ou sortant)

Avec la diffusion PHONE_STATE, nous n'avons pas besoin d'utiliser l'autorisation PROCESS_OUTGOING_CALLS ou l'action NEW_OUTGOING_CALL obsolète.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.