130 votes

Comment passer un appel téléphonique dans Android et revenir à mon activité lorsque l'appel est terminé ?

Je lance une activité pour passer un appel téléphonique, mais lorsque j'appuie sur le bouton "Terminer l'appel", je ne reviens pas à mon activité. Pouvez-vous me dire comment je peux lancer une activité d'appel qui revient à moi lorsque j'appuie sur le bouton "End call" ? C'est ainsi que je passe l'appel téléphonique :

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

106voto

moonlightcheese Points 4818

Utilisez un PhoneStateListener pour savoir quand l'appel est terminé. Vous aurez probablement besoin de déclencher les actions de l'écouteur pour attendre le début de l'appel (attendre jusqu'à ce que l'état PHONE_STATE_OFFHOOK passe à nouveau à PHONE_STATE_IDLE) et ensuite écrire du code pour ramener votre application à l'état IDLE.

il se peut que vous deviez exécuter le listener dans un service pour vous assurer qu'il reste actif lorsque votre application est redémarrée. quelques exemples de code :

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

Définition de l'auditeur :

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

Dans votre Manifest.xml ajoutez la permission suivante :

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

10 votes

N'oubliez pas la permission. ;)

5 votes

Comme l'a noté Gp2mv3, n'oubliez pas d'ajouter la permission READ_PHONE_STATE au fichier AndroidManifest.xml.

6 votes

@moonlightcheese Pouvez-vous ajouter du code pour revenir à notre application depuis l'application d'appel ?

50voto

Pria Points 378

Ceci concerne la question posée par Starter.

Le problème avec votre code est que vous ne passez pas le numéro correctement.

Le code devrait être :

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

N'oubliez pas d'ajouter la permission dans le fichier manifeste.

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

ou

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

pour le numéro d'urgence en cas DIAL est utilisé.

7 votes

J'ai du mal à voir en quoi votre code est différent du code de la question originale.

0 votes

Le code n'est pas différent. Vous devez ajouter la permission dans le fichier manifest.

4 votes

Android.permission.CALL_PRIVILEGED L'autorisation est uniquement accordée aux applications système et n'est pas disponible au niveau des applications.

25voto

André Lima Points 461

Nous avons eu le même problème et avons réussi à le résoudre en utilisant une PhoneStateListener pour identifier quand l'appel se termine, mais en plus nous devions finish() l'activité initiale avant de la reprendre avec startActivity sinon le journal des appels serait devant.

5 votes

Vous pouvez éviter ce problème en utilisant une méthode différente. Si vous construisez un ContentObserver qui observe le journal des appels Android, l'application ne démarrera pas tant que le journal des appels n'aura pas été modifié. En fait, j'ai dû me débarrasser du PhoneStateListener en faveur de ce modèle, car mon application avait besoin des données du journal des appels, et l'écouteur renvoyait les données avant que les changements ne soient effectués. pastebin.com/bq2s9EVa

11 votes

@André : votre lien semble être cassé

0 votes

Je vous donnerais bien un million de réputation (si j'en avais beaucoup :)) Merci d'avoir fait ma journée !

13voto

TheSolarSheriff Points 111

J'ai trouvé que le EndCallListener était l'exemple le plus fonctionnel, pour obtenir le comportement décrit (finish(), call, restart) j'ai ajouté quelques SharedPreferences pour que le Listener ait une référence pour gérer ce comportement.

Mes OnClick, initialise et EndCallListener ne répondent qu'aux appels de l'application. Les autres appels sont ignorés.

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

        }

    }
}

ajoutez-les à 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>

et quelque chose comme ceci dans votre Manifeste si vous avez besoin de revenir à l'aspect et à la sensation avant l'appel

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

et mettez-les dans votre "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()

Utilisez ceci pour initialiser le comportement de votre onClick dans monActivité, par exemple après 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();

}

Vous devriez constater qu'en cliquant sur votre liste de numéros de téléphone, vous terminez votre activité, passez l'appel au numéro et revenez à votre activité lorsque l'appel est terminé.

Passer un appel depuis l'extérieur de votre application alors qu'elle est toujours active ne redémarrera pas votre activité (sauf s'il s'agit du même numéro que le dernier numéro de BParty appelé).

)

5 votes

Désolé, mais ce code est plutôt moche. Merci quand même pour la réponse

7voto

yakr Points 1

Vous pouvez utiliser startActivityForResult()

1 votes

Sous Android 5.0, la méthode onActivityResult est appelée dès le début de l'appel !

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