Come rilevare le chiamate in arrivo, su un dispositivo Android?


130

Sto cercando di fare un'app come, quando arriva una chiamata al telefono, voglio rilevare il numero. Di seguito è quello che ho provato, ma non rileva le chiamate in arrivo.

Voglio eseguire il mio MainActivityin background, come posso farlo?

Avevo dato il permesso in manifestarchivio.

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

C'è qualcos'altro che devo fornire nel manifest?

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

cosa dovremmo fare per Android P
Ahmad Arslan

Risposte:


336

Ecco cosa uso per fare questo:

Manifesto:

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

Il rilevatore di chiamate riutilizzabile di 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;
    }
}

Quindi per usarlo, basta derivarne una classe e implementare alcune semplici funzioni, qualunque sia il tipo di chiamata che ti interessa:

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)
    {
        //
    }

}

Inoltre puoi vedere una recensione che ho fatto sul perché il codice è come sul mio blog . Gist link: https://gist.github.com/ftvs/e61ccb039f511eb288ee

EDIT: aggiornato al codice più semplice, poiché ho rielaborato la classe per uso personale


2
Questo codice non mostra nulla. Quello che fa è chiamarti quando una chiamata in uscita inizia / termina e ti passa il numero, l'ora di inizio e l'ora di fine. In realtà visualizzarlo è il tuo lavoro, perché non ho modo di sapere come lo desideri.
Gabe Sechan,

3
@GabeSechan: Fantastico! mi può guidare per favore per gestire la situazione di chiamata in attesa?
Mehul Joisar,

6
Solo per aggiungere a questo, non ha funzionato quando l'app non era in primo piano o in background fino a quando non l'ho aggiunto nel ricevitore: "android: enabled =" true "
Rajat Sharma,

1
Le variabili statiche rimarranno attive fino a quando l'applicazione non viene espulsa dalla memoria (che può richiedere parecchio tempo, a seconda se i servizi sono in esecuzione e le condizioni generali di memoria del telefono). Ma sì, possono essere persi. Puoi scriverlo su disco, ad esempio tramite preferenza condivisa, ma ciò può causare anche risultati falsi; ti impedirebbe di avere i dati correttamente cancellati in diversi casi, come ad esempio il riavvio del telefono. Nel mio caso d'uso i rari dati nulli e persi erano migliori dei dati errati. Sentiti libero di scherzare con questo per le tue esigenze.
Gabe Sechan,

1
@GabeSechan: sembra che ci sia un bug. lastState non dovrebbe essere inizializzato a CALL_STATE_IDLE. Mi mancano alcune chiamate quando la mia app viene uccisa mentre lo stato corrente è RINGING. Perché quando diventa di IDLEnuovo al termine della chiamata, la variabile statica viene reinizializzata CALL_STATE_IDLEe non si riavvia facendo nulla. Quindi perdiamo il riferimento a lastState.
Heisenberg,

23
private MyPhoneStateListener phoneStateListener = new MyPhoneStateListener();

registrare

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

e annullare la registrazione

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

dove dovrei usarlo nella mainattività?
Jesbin MJ,

inseriscilo nella classe in cui stai ascoltando il cambiamento .. normalmente i registri sono fatti in oncreate e non registrati in ondestroy .. dichiara l'oggetto globalmente nella classe
stinepike

Questa opzione non richiede autorizzazioni.
Mike,

mentre la soluzione di Gabe è più adatta a funzioni più invadenti, ad esempio il tipo di app Viber, questa è la soluzione migliore per coloro che hanno semplicemente bisogno di reagire alle azioni dell'utente di partecipare a una telefonata. Richiedere l'autorizzazione di runtime in casi come questo è molto probabilmente un problema eccessivo e potrebbe non essere ben accolto dall'utente.
Bosfera,

1
Voglio fare qualcosa, quando arriva la chiamata, come fare con questo codice?
Noor Hossain,

14

Con Android P - Api Livello 28: devi ottenere l'autorizzazione READ_CALL_LOG

Accesso limitato ai registri delle chiamate

Android P muove le CALL_LOG, READ_CALL_LOG, WRITE_CALL_LOG, e PROCESS_OUTGOING_CALLSle autorizzazioni dal PHONEgruppo di autorizzazioni per il nuovo CALL_LOGgruppo di autorizzazioni. Questo gruppo offre agli utenti un migliore controllo e visibilità delle app che richiedono l'accesso a informazioni riservate sulle chiamate telefoniche, come la lettura dei registri delle chiamate e l'identificazione dei numeri di telefono.

Per leggere i numeri dall'azione intento PHONE_STATE, deviREAD_CALL_LOGREAD_PHONE_STATE disporre sia dell'autorizzazione che dell'autorizzazione . Per leggere i numeri da onCallStateChanged(), ora è necessaria READ_CALL_LOGsolo l' autorizzazione. Non hai più bisogno del READ_PHONE_STATEpermesso.


per coloro che sono solo l'aggiunta READ_CALL_LOGdi AndroidManifest.xmlconcentrarsi sull'aggiunta di una richiesta di autorizzazione in MainActivity.
Piyush,

13

AGGIORNAMENTO: Il codice davvero fantastico pubblicato da Gabe Sechan non funziona più a meno che tu non richieda esplicitamente all'utente di concedere le autorizzazioni necessarie. Ecco un codice che puoi inserire nella tua attività principale per richiedere queste autorizzazioni:

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

ANCHE: Come qualcuno ha menzionato in un commento sotto il post di Gabe , devi aggiungere un piccolo frammento di codice android:enabled="trueal destinatario per rilevare le chiamate in arrivo quando l'app non è attualmente in esecuzione in primo piano:

    <!--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>

Che cosa succede se l'applicazione non ha alcuna attività e solo il ricevitore e un servizio. Quindi da dove scriviamo questo codice per ottenere l'autorizzazione da parte dell'utente in quanto il broadcastreceiver non verrà chiamato fino a quando non viene data questa autorizzazione.
user2779311

2
Hai almeno bisogno di un MainActivity anche se è aperto solo una volta. Prendi ad esempio la mia app di blocco delle chiamate RoboStop: quando l'utente scarica l'app per la prima volta, quindi fa clic sull'icona dell'app per avviare l'app, viene richiesto di concedere alla mia app le autorizzazioni necessarie. L'app dispone anche di un pulsante per abilitare / disabilitare il blocco delle chiamate, ma l'utente non deve riavviare l'app / l'attività, il blocco delle chiamate avverrà in background senza che l'utente debba riavviare l'app / l'attività.
topherPedersen,

Coloro che hanno difficoltà a implementarlo, seguono questo tutorial studytutorial.in/…
Prasath,

5

questo può aiutarti e anche aggiungere richiedere l'autorizzazione

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
questo sembra andare bene. Ma come posso usarlo dall'attività? per favore dimmi i dettagli
Amir


2

Ecco un metodo semplice che può evitare l'uso PhonestateListenere altre complicazioni.
Quindi qui stiamo ricevendo i 3 eventi da Android come RINGING, OFFHOOKe IDLE. E al fine di ottenere il tutto il possibile stato di chiamata, abbiamo bisogno di definire i nostri Stati come RINGING, OFFHOOK, IDLE, FIRST_CALL_RINGING, SECOND_CALL_RINGING. Può gestire tutti gli stati in una telefonata.
Pensa in un modo che stiamo ricevendo eventi da Android e definiremo i nostri stati di chiamata. Vedi il codice

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, grazie per il tuo codice. Funziona bene tranne il onOutgoingCallEnded(). Non viene mai eseguito. I telefoni di prova sono Samsung S5 e Trendy. Ci sono 2 bug, penso.

1: manca una coppia di parentesi.

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: lastStatenon viene aggiornato dal statese si trova alla fine della funzione. Dovrebbe essere sostituito alla prima riga di questa funzione da

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;
    }
    //....
}

Ulteriori ho messo lastStatee savedNumberin preferenze condivise come hai suggerito.

Ho appena provato con le modifiche sopra. Bug risolto almeno sui miei telefoni.


0

Si prega di utilizzare il seguente codice. Ti aiuterà a ottenere il numero in entrata con altri dettagli di chiamata.

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

} 

e nella richiesta manifest per le seguenti autorizzazioni:

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

In questo modo READ_LOGS ti farà bandire l'app dal Play Store
Duna il

0

È necessario un BroadcastReceiver per ACTION_PHONE_STATE_CHANGEDQuesto chiamerà il tuo ricevuto ogni volta che lo stato del telefono cambia da inattivo, squillo, sganciato dal valore precedente e dal nuovo valore che puoi rilevare se si tratta di una chiamata in entrata / in uscita.

L'autorizzazione richiesta sarebbe:

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

Ma se vuoi ricevere anche EXTRA_INCOMING_NUMBER in quella trasmissione, avrai bisogno di un'altra autorizzazione: "android.permission.READ_CALL_LOG"

E il codice è qualcosa del genere:

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()
}

e nella classe del ricevitore, possiamo ottenere lo stato corrente leggendo l'intento in questo modo:

intent.extras["state"]

il risultato di extra potrebbe essere:

SUONERIA -> Se il telefono squilla

OFFHOOK -> Se stai parlando con qualcuno (chiamata in arrivo o in uscita)

IDLE -> se la chiamata è terminata (chiamata in arrivo o in uscita)

Con la trasmissione PHONE_STATE non è necessario utilizzare l'autorizzazione PROCESS_OUTGOING_CALLS o l'azione NEW_OUTGOING_CALL obsoleta.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.