Come effettuare una chiamata su Android e tornare alla mia attività al termine della chiamata?


129

Sto avviando un'attività per effettuare una chiamata, ma quando ho premuto il pulsante "Termina", questa non ritorna alla mia attività. Puoi dirmi come posso avviare un'attività di chiamata che mi viene restituita quando viene premuto il pulsante "Termina chiamata"? Ecco come sto effettuando la telefonata:

    String url = "tel:3334444";
    Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));

Risposte:


106

utilizzare un PhoneStateListener per vedere quando termina la chiamata. molto probabilmente dovrai attivare le azioni dell'ascoltatore per attendere l'avvio di una chiamata (attendi fino a quando non viene nuovamente modificata da PHONE_STATE_OFFHOOK a PHONE_STATE_IDLE) e quindi scrivi del codice per riportare la tua app nello stato IDLE.

potrebbe essere necessario eseguire l'ascoltatore in un servizio per assicurarsi che rimanga attivo e che l'app venga riavviata. qualche codice di esempio:

EndCallListener callListener = new EndCallListener();
TelephonyManager mTM = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
mTM.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE);

Definizione dell'ascoltatore:

private class EndCallListener extends PhoneStateListener {
    @Override
    public void onCallStateChanged(int state, String incomingNumber) {
        if(TelephonyManager.CALL_STATE_RINGING == state) {
            Log.i(LOG_TAG, "RINGING, number: " + incomingNumber);
        }
        if(TelephonyManager.CALL_STATE_OFFHOOK == state) {
            //wait for phone to go offhook (probably set a boolean flag) so you know your app initiated the call.
            Log.i(LOG_TAG, "OFFHOOK");
        }
        if(TelephonyManager.CALL_STATE_IDLE == state) {
            //when this state occurs, and your flag is set, restart your app
            Log.i(LOG_TAG, "IDLE");
        }
    }
}

Nel tuo Manifest.xmlfile aggiungi la seguente autorizzazione:

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

10
Non dimenticare il permesso. ;)
Gp2mv3,

5
Come ha notato Gp2mv3, non dimenticare di aggiungere l'autorizzazione READ_PHONE_STATE ad AndroidManifest.xml.
Cooper,

6
@moonlightcheese Puoi aggiungere il codice per tornare alla nostra app dall'app di chiamata?
Geek,

questo è pericoloso perché aprirà sempre l'attività della tua app ogni volta che chiami
user924

49

Questo riguarda la domanda posta da Starter.

Il problema con il tuo codice è che non stai passando il numero correttamente.

Il codice dovrebbe essere:

private OnClickListener next = new OnClickListener() {

     public void onClick(View v) {
        EditText num=(EditText)findViewById(R.id.EditText01); 
        String number = "tel:" + num.getText().toString().trim();
        Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse(number)); 
        startActivity(callIntent);
    }
};

Non dimenticare di aggiungere l'autorizzazione nel file manifest.

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

o

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

per il numero di emergenza nel caso DIALvenga utilizzato.


7
Sto facendo fatica a vedere come il tuo codice è diverso dal codice nella domanda originale
Elijah Saounkine

Il codice non è diverso. Devi aggiungere l'autorizzazione nel file manifest.
Pria

4
android.permission.CALL_PRIVILEGED L'autorizzazione è concessa solo alle app di sistema non disponibili a livello di app.
CoDe

e che cos'è? non tornerà alla tua attività
user924

24

Abbiamo avuto lo stesso problema e siamo riusciti a risolverlo utilizzando a PhoneStateListenerper identificare quando termina la chiamata, ma abbiamo anche dovuto finish()l'attività originale prima di ricominciare da capo startActivity, altrimenti il ​​registro delle chiamate si troverebbe di fronte.


4
puoi evitarlo usando un metodo diverso. se si crea un ContentObserver che osserva il registro delle chiamate Android, l'app non si avvierà fino a quando non viene apportata la modifica del registro delle chiamate. in realtà ho dovuto scaricare PhoneStateListener in favore di questo modello, poiché la mia app aveva bisogno dei dati del registro delle chiamate e l'ascoltatore stava tornando prima che fossero apportate tali modifiche. pastebin.com/bq2s9EVa
moonlightcheese

11
@ André: il tuo collegamento sembra non funzionare
aggregate1166877,

Ti darei un milione di reputazione (se avessi molto :)) Grazie per aver reso la mia giornata!
keybee

1
Il problema con i collegamenti dico!
Dheeraj Bhaskar,


13

Ho trovato l'EndCallListener l'esempio più funzionale, per ottenere il comportamento descritto (finish (), call, restart) ho aggiunto alcune SharedPreferences in modo che il Listener avesse un riferimento per gestire questo comportamento.

My OnClick, initialise e EndCallListener rispondono solo alle chiamate dall'app. Altre chiamate ignorate.

import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;

public class EndCallListener extends PhoneStateListener {

private String TAG ="EndCallListener";
private int     LAUNCHED = -1;

SharedPreferences prefs = PreferenceManager
                            .getDefaultSharedPreferences(
                                myActivity.mApp.getBaseContext());

SharedPreferences.Editor _ed = prefs.edit();

@Override
    public void onCallStateChanged(int state, String incomingNumber) {
    String _prefKey = myActivity.mApp                          
                      .getResources().getString(R.string.last_phone_call_state_key),
    _bPartyNumber = myActivity.mApp                           
                      .getResources().getString(R.string.last_phone_call_bparty_key);

    int mLastCallState = prefs.getInt(_prefKey, LAUNCHED);

    //Save current call sate for next call
    _ed.putInt(_prefKey,state);
    _ed.commit();

        if(TelephonyManager.CALL_STATE_RINGING == state) {
            Log.i(TAG, " >> RINGING, number: " + incomingNumber);
        }
        if(TelephonyManager.CALL_STATE_IDLE == state && mLastCallState != LAUNCHED ) {
            //when this state occurs, and your flag is set, restart your app

            if (incomingNumber.equals(_bPartyNumber) == true) {
                //Call relates to last app initiated call
            Intent  _startMyActivity =  
               myActivity.mApp                               
               .getPackageManager()                                  
               .getLaunchIntentForPackage(
                 myActivity.mApp.getResources()
                 .getString(R.string.figjam_package_path));

_startMyActivity.setAction(                                     
        myActivity.mApp.getResources()
        .getString(R.string.main_show_phone_call_list));

                myActivity.mApp
                        .startActivity(_startMyActivity);
                Log.i(TAG, "IDLE >> Starting MyActivity with intent");
            }
            else
                Log.i(TAG, "IDLE after calling "+incomingNumber);

        }

    }
}

aggiungili a strings.xml

<string name="main_show_phone_call_list">android.intent.action.SHOW_PHONE_CALL_LIST</string>
<string name="last_phone_call_state_key">activityLpcsKey</string>
<string name="last_phone_call_bparty_key">activityLpbpKey</string>

e qualcosa del genere nel tuo Manifesto se devi tornare all'aspetto e alla sensazione prima della chiamata

  <activity android:label="@string/app_name" android:name="com.myPackage.myActivity" 
      android:windowSoftInputMode="stateHidden"
        android:configChanges="keyboardHidden" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <action android:name="android.intent.action.SHOW_PHONE_CALL_LIST" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
  </activity>

e inseriscili nel tuo "myActivity"

public static Activity mApp=null; //Before onCreate()
  ...
onCreate( ... ) {
  ...
if (mApp == null) mApp = this; //Links your resources to other classes
  ...
    //Test if we've been called to show phone call list
    Intent _outcome = getIntent();
    String _phoneCallAction = mApp.getResources().getString(R.string.main_show_phone_call_list);
    String _reqAction = _outcome.getAction();//Can be null when no intent involved

         //Decide if we return to the Phone Call List view
         if (_reqAction != null &&_reqAction.equals(_phoneCallAction) == true) {
                         //DO something to return to look and feel
         }

  ...
        myListView.setOnItemClickListener(new OnItemClickListener() { //Act on item when selected
             @Override
             public void onItemClick(AdapterView<?> a, View v, int position, long id) {

                 myListView.moveToPosition(position);
                 String _bPartyNumber = "tel:"+myListView.getString(myListView.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); 

                 //Provide an initial state for the listener to access.
                 initialiseCallStatePreferences(_bPartyNumber);

                 //Setup the listener so we can restart myActivity
                    EndCallListener _callListener = new EndCallListener();
                    TelephonyManager _TM = (TelephonyManager)mApp.getSystemService(Context.TELEPHONY_SERVICE);

                    _TM.listen(_callListener, PhoneStateListener.LISTEN_CALL_STATE);

                         Intent _makeCall = new Intent(Intent.ACTION_CALL, Uri.parse(_bPartyNumber));

                 _makeCall.setComponent(new ComponentName("com.android.phone","com.android.phone.OutgoingCallBroadcaster"));
                    startActivity(_makeCall);                           
                finish();
              //Wait for call to enter the IDLE state and then we will be recalled by _callListener
              }
        });


}//end of onCreate()

usalo per inizializzare il comportamento del tuo onClick in myActivity ad es. dopo onCreate ()

private void initialiseCallStatePreferences(String _BParty) {
    final int LAUNCHED = -1;
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
                                mApp.getBaseContext());
    SharedPreferences.Editor _ed = prefs.edit();

    String _prefKey = mApp.getString(R.string.last_phone_call_state_key),
           _bPartyKey = mApp.getString(R.string.last_phone_call_bparty_key);

    //Save default call state before next call
        _ed.putInt(_prefKey,LAUNCHED);
        _ed.putString(_bPartyKey,_BParty);
        _ed.commit();

}

Dovresti scoprire che facendo clic sul tuo elenco di numeri di telefono termina la tua attività, effettua la chiamata al numero e ritorna alla tua attività al termine della chiamata.

Effettuare una chiamata dall'esterno dell'app mentre è ancora in giro non riavvierà la tua attività (a meno che non sia uguale all'ultimo numero BParty chiamato).

:)


5
Ci dispiace ma questo codice sembra un po 'brutto. Grazie per la risposta, però
Pierre,

7

puoi usare startActivityForResult ()


1
Usando Android 5.0 il metodo onActivityResult è chiamare immediatamente la chiamata inizia !!
Panciz,

6

Questa è una soluzione dal mio punto di vista:

ok.setOnClickListener(this);
@Override
public void onClick(View view) {
    if(view == ok){
        Intent intent = new Intent(Intent.ACTION_CALL);
        intent.setData(Uri.parse("tel:" + num));
        activity.startActivity(intent);

    }

Naturalmente nella definizione dell'attività (classe) devi implementare View.OnClickListener.


6

Ecco il mio esempio, prima l'utente può scrivere il numero che desidera comporre, quindi preme un pulsante di chiamata e viene indirizzato al telefono. Dopo l'annullamento della chiamata, l'utente viene rinviato all'applicazione. Per fare ciò, il pulsante deve avere un metodo onClick ('makePhoneCall' in questo esempio) nel file XML. È inoltre necessario registrare l'autorizzazione nel manifest.

Manifesto

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

Attività

import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

public class PhoneCall extends Activity {

    EditText phoneTo;

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

        phoneTo = (EditText) findViewById(R.id.phoneNumber);

    }
    public void makePhoneCall(View view) {




        try {
            String number = phoneTo.getText().toString();
            Intent phoneIntent = new Intent(Intent.ACTION_CALL);
            phoneIntent.setData(Uri.parse("tel:"+ number));
            startActivity(phoneIntent);


        } catch (android.content.ActivityNotFoundException ex) {
            Toast.makeText(PhoneCall.this,
                    "Call failed, please try again later!", Toast.LENGTH_SHORT).show();
        }
    }

}

XML

 <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:inputType="phone"
        android:ems="10"
        android:id="@+id/phoneNumber"
        android:layout_marginTop="67dp"
        android:layout_below="@+id/textView"
        android:layout_centerHorizontal="true" />

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Call"
        android:id="@+id/makePhoneCall"
        android:onClick="makePhoneCall"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true" />

non hai nemmeno quello di cui stai parlando. READ_PHONE_STATE - non lo usi nel tuo codice di esempio, perché l'hai aggiunto? ovviamente ti riporterà all'attività della tua app se premi il pulsante di annullamento, ma l'autore della domanda ha chiesto come tornare all'attività dopo l'accettazione della chiamata
user924

6
@Override
public void onClick(View view) {
    Intent phoneIntent = new Intent(Intent.ACTION_CALL);
    phoneIntent.setData(Uri.parse("tel:91-000-000-0000"));
    if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    startActivity(phoneIntent);
}

5

Se hai intenzione di usare un ascoltatore dovrai aggiungere anche questa autorizzazione al manifest.

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

3

All'interno di PhoneStateListener dopo aver visto la chiamata è finita meglio usare:

Intent intent = new Intent(CallDispatcherActivity.this, CallDispatcherActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

Dove CallDispatcherActivity è l'attività in cui l'utente ha lanciato una chiamata (a un dispatcher del servizio taxi, nel mio caso). Questo rimuove semplicemente l'app di telefonia Android dall'alto, l'utente torna al posto del brutto codice che ho visto qui.


1
E non dimenticare di rimuovere l'ascoltatore dopo aver fatto la telefonata, in questo modo:((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE);
Dmitri Novikov,

Ho provato ad usare il tuo approccio ma l'attività (chiamata ControlPanel) non viene riattivata. Il display continua a mostrare l'interfaccia del combinatore telefonico e i logger sui punti di ingresso onResume e onNewIntent in ControlPanel sono completamente silenziosi. Ecco l'intento: Intent intentRestart = new Intent(ControlPanel.this, ControlPanel.class);. Vorrei sottolineare che PhoneStateListener si trova anche in ControlPanel. Vale a dire, il mio obiettivo è ripristinare l'interfaccia utente allo stato in cui si trovava prima di iniziare la telefonata. Eventuali suggerimenti?
PeteH

Prova ad accedere all'interno dell'implementazione di PhoneStateListener.
Dmitri Novikov il

3

Per tornare al tuo Activity, dovrai ascoltare TelephonyStates. Su questo listenerpuoi inviare un Intentper riaprire il tuoActivity quando il telefono è inattivo.

Almeno questo è come lo farò.


3
  Intent callIntent = new Intent(Intent.ACTION_CALL);  
  callIntent.setData(Uri.parse("tel:"+number));  
   startActivity(callIntent);   

 **Add permission :**

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

2

Prova a usare:

finish();

alla fine dell'attività. Ti reindirizzerà alla tua attività precedente.


2

Quando PhoneStateListenerviene utilizzato, è necessario assicurarsi che sia PHONE_STATE_IDLEseguito quanto segue PHONE_STATE_OFFHOOKper attivare l'azione da eseguire dopo la chiamata. Se il trigger si verifica dopo aver visto PHONE_STATE_IDLE, finirai per farlo prima della chiamata. Perché vedrai cambiare lo statoPHONE_STATE_IDLE -> PHONE_STATE_OFFHOOK -> PHONE_STATE_IDLE.


non è possibile che l'app si interrompa quando si apre la schermata della chiamata in corso?
lisovaccaro,

L'oggetto Listener, una volta impostato per ascoltare TelephonyManager ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(new PhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE), continuerà ad ascoltare lo stato del telefono e ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE)
resterà

2

// in setonclicklistener inserisci questo codice:

EditText et_number=(EditText)findViewById(R.id.id_of_edittext); 
String my_number = et_number.getText().toString().trim();
Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse(my_number)); 
startActivity(callIntent);

// autorizza la chiamata in manifest:

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

1

@Dmitri Novikov, FLAG_ACTIVITY_CLEAR_TOPcancella qualsiasi istanza attiva in cima a quella nuova. Pertanto, potrebbe terminare la vecchia istanza prima di completare il processo.



1

passi:

1) Aggiungi le autorizzazioni richieste nel Manifest.xmlfile.

<!--For using the phone calls -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<!--For reading phone call state-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

2) Creare un listener per le modifiche allo stato del telefono.

public class EndCallListener extends PhoneStateListener {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
    if(TelephonyManager.CALL_STATE_RINGING == state) {
    }
    if(TelephonyManager.CALL_STATE_OFFHOOK == state) {
        //wait for phone to go offhook (probably set a boolean flag) so you know your app initiated the call.
    }
    if(TelephonyManager.CALL_STATE_IDLE == state) {
        //when this state occurs, and your flag is set, restart your app
    Intent i = context.getPackageManager().getLaunchIntentForPackage(
                            context.getPackageName());
    //For resuming the application from the previous state
    i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

    //Uncomment the following if you want to restart the application instead of bring to front.
    //i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    context.startActivity(i);
    }
}
}

3) Inizializza l'ascoltatore nel tuo OnCreate

EndCallListener callListener = new EndCallListener();
TelephonyManager mTM = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
mTM.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE);

ma se si desidera ripristinare l'ultimo stato dell'applicazione o ripristinarlo dallo stack posteriore , sostituirloFLAG_ACTIVITY_CLEAR_TOP conFLAG_ACTIVITY_SINGLE_TOP

Fai riferimento a questa risposta



0

Quando si avvia la chiamata, sembra a posto.

C'è una differenza tra Android 11+ e down nel portare la tua app in primo piano.

Android 10 o meno, devi iniziare un nuovo intento, Android 11+ che usi semplicemente BringTaskToFront

Nello stato di chiamata IDLE:

if (Build.VERSION.SDK_INT >= 11) {
    ActivityManager am = (ActivityManager) activity.getSystemService(Activity.ACTIVITY_SERVICE);
    am.moveTaskToFront(MyActivity.MyActivityTaskId, ActivityManager.MOVE_TASK_WITH_HOME);
} else {
    Intent intent = new Intent(activity, MyActivity.class);
    activity.startActivity(intent);
}

Ho impostato il MyActivity.MyActivityTaskIdquando si effettua la chiamata sulla mia attività in questo modo, se non funziona, ho impostato questa variabile nella pagina delle attività principali della pagina in cui vuoi tornare.

MyActivity.MyActivityTaskId = this.getTaskId();

MyActivityTaskId è una variabile statica sulla mia classe di attività

public static int MyActivityTaskId = 0;

Spero che questo funzioni per te. Uso il codice sopra riportato in modo leggermente diverso, apro la mia app non appena si risponde alla chiamata in modo che l'utente possa vedere i dettagli del chiamante.

Ho inserito anche alcune cose AndroidManifest.xml:

/*Dont really know if this makes a difference*/
<activity android:name="MyActivity" android:taskAffinity="" android:launchMode="singleTask" />

e permessi:

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

Ti preghiamo di porre domande se o quando rimani bloccato.

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.