Comment passer un appel téléphonique sous Android et revenir à mon activité une fois l'appel terminé?


129

Je lance une activité pour passer un appel téléphonique, mais lorsque j'ai appuyé sur le bouton «terminer l'appel», cela ne revient pas à mon activité. Pouvez-vous s'il vous plaît me dire comment puis-je lancer une activité d'appel qui me revient lorsque vous appuyez sur le bouton «Fin d'appel»? Voici comment je passe l'appel téléphonique:

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

Réponses:


106

utilisez un PhoneStateListener pour voir quand l'appel est terminé. vous devrez probablement déclencher les actions de l'écouteur pour attendre le début de l'appel (attendez que le PHONE_STATE_OFFHOOK soit à nouveau remplacé par PHONE_STATE_IDLE), puis rédigez du code pour ramener votre application à l'état IDLE.

vous devrez peut-être exécuter l'écouteur dans un service pour vous assurer qu'il reste actif et que votre application est redémarrée. un exemple 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.xmlfichier, ajoutez l'autorisation suivante:

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

10
N'oubliez pas la permission. ;)
Gp2mv3

5
Comme Gp2mv3 l'a noté, n'oubliez pas d'ajouter l'autorisation READ_PHONE_STATE à AndroidManifest.xml.
Cooper

6
@moonlightcheese Pouvez-vous ajouter du code pour revenir à notre application à partir de l'application d'appel?
Geek

ceci est dangereux car cela ouvrira toujours l'activité de votre application chaque fois que vous appelez
user924

49

Ceci concerne la question posée par Starter.

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

Le code doit ê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 l'autorisation 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 d' DIALutilisation.


7
J'ai du mal à voir en quoi votre code est différent du code de la question d'origine
Elijah Saounkine

Le code n'est pas différent. Vous devez ajouter l'autorisation dans le fichier manifeste.
Pria

4
android.permission.CALL_PRIVILEGED L'autorisation n'est accordée qu'aux applications système non disponibles au niveau de l'application.
CoDe

et qu'est ce que c'est que ça? il ne reviendra pas à votre activité
user924

24

Nous avons eu le même problème et avons réussi à le résoudre en utilisant un PhoneStateListenerpour identifier la fin de l'appel, mais en plus, nous devions effectuer finish()l'activité d'origine avant de la redémarrer startActivity, sinon le journal des appels serait devant.


4
vous pouvez éviter cela en utilisant une méthode différente. si vous créez un ContentObserver qui observe le journal des appels Android, l'application ne démarrera pas tant que la modification du journal des appels n'aura pas été effectuée. En fait, j'ai dû vider le PhoneStateListener en faveur de ce modèle, car mon application avait besoin de données du journal des appels et l'auditeur revenait avant que ces modifications ne soient apportées. pastebin.com/bq2s9EVa
moonlightcheese

11
@ André: votre lien semble être rompu
aggregate1166877

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

1
Le problème avec les liens je dis!
Dheeraj Bhaskar


13

J'ai trouvé EndCallListener l'exemple le plus fonctionnel, pour obtenir le comportement décrit (finish (), appel, redémarrage), j'ai ajouté quelques SharedPreferences afin que l'auditeur ait une référence pour gérer ce comportement.

My OnClick, initialise et EndCallListener ne répondent qu'aux appels de l'application. Autres appels 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 ça dans votre manifeste si vous avez besoin de revenir à l'apparence 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 initier le comportement de votre onClick dans myActivity, 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 que cliquer sur votre liste de numéros de téléphone termine votre activité, appelle le numéro et revient à votre activité lorsque l'appel se termine.

Passer un appel depuis l'extérieur de votre application alors qu'elle est toujours là ne redémarrera pas votre activité (à moins que ce ne soit le même que le dernier numéro BParty appelé).

:)


5
Désolé mais ce code semble un peu moche. Merci pour la réponse
Pierre

7

vous pouvez utiliser startActivityForResult ()


1
En utilisant Android 5.0, la méthode onActivityResult est appelée immédiatement l'appel commence !!
Panciz

6

C'est la solution de mon point de vue:

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

    }

Bien sûr, dans la définition d'activité (classe), vous devez implémenter View.OnClickListener.


6

Voici mon exemple, d'abord l'utilisateur doit écrire le numéro qu'il souhaite composer, puis appuie sur un bouton d'appel et est dirigé vers le téléphone. Après l'annulation de l'appel, l'utilisateur est renvoyé vers l'application. Pour cela, le bouton doit avoir une méthode onClick ('makePhoneCall' dans cet exemple) dans le xml. Vous devez également enregistrer l'autorisation dans le manifeste.

Manifeste

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

Activité

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

vous ne savez même pas ce dont vous parlez. READ_PHONE_STATE - vous ne l'utilisez pas dans votre exemple de code, pourquoi l'avez-vous ajouté? bien sûr, cela vous ramènera à l'activité de votre application si vous appuyez sur le bouton d'annulation, mais l'auteur de la question posée sur la façon de revenir à l'activité après l'acceptation de l'appel
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

Si vous comptez utiliser un écouteur, vous devrez également ajouter cette autorisation au manifeste.

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

3

À l'intérieur de PhoneStateListener après avoir vu l'appel est terminé, une meilleure utilisation:

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

Où CallDispatcherActivity est l'activité où l'utilisateur a lancé un appel (vers un répartiteur de service de taxi, dans mon cas). Cela supprime simplement l'application de téléphonie Android du haut, l'utilisateur récupère au lieu du code laid que j'ai vu ici.


1
Et n'oubliez pas de retirer l'auditeur une fois l'appel téléphonique terminé, comme ceci:((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE);
Dmitri Novikov

J'ai essayé d'utiliser votre approche mais l'activité (appelée ControlPanel) n'est pas réactivée. L'écran continue d'afficher l'interface du numéroteur téléphonique et les enregistreurs sur les points d'entrée onResume et onNewIntent dans ControlPanel sont complètement silencieux. Voici l'intention: Intent intentRestart = new Intent(ControlPanel.this, ControlPanel.class);. Je dois souligner que PhoneStateListener est également dans ControlPanel. C'est-à-dire que mon objectif est de restaurer l'interface utilisateur dans l'état dans lequel elle se trouvait avant de lancer l'appel téléphonique. Aucune suggestion?
PeteH

Essayez de vous connecter à l'intérieur de votre implémentation PhoneStateListener.
Dmitri Novikov

3

Pour revenir au vôtre Activity, vous devrez écouter TelephonyStates. Sur cela, listenervous pouvez envoyer un Intentpour rouvrir votre Activityune fois que le téléphone est inactif.

Au moins c'est comme ça que je vais le faire.


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

Essayez d'utiliser:

finish();

à la fin de l'activité. Il vous redirigera vers votre activité précédente.


2

Quand PhoneStateListenerest utilisé, il faut s'assurer que le PHONE_STATE_IDLEsuivant PHONE_STATE_OFFHOOKest utilisé pour déclencher l'action à effectuer après l'appel. Si le déclencheur se produit en voyant PHONE_STATE_IDLE, vous finirez par le faire avant l'appel. Parce que tu verras l'état changerPHONE_STATE_IDLE -> PHONE_STATE_OFFHOOK -> PHONE_STATE_IDLE.


n'est-il pas possible que l'application s'arrête lorsque l'écran d'appel en cours s'ouvre?
lisovaccaro

L'objet d'écoute une fois défini pour écouter le TelephonyManager avec ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(new PhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE)continuera à écouter l'état du téléphone et sera actif jusqu'à ce qu'il soit explicitement arrêté avec((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE)
PonMaran

2

// dans setonclicklistener mettez ce code:

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

// donne la permission d'appeler dans le manifeste:

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

1

@Dmitri Novikov, FLAG_ACTIVITY_CLEAR_TOPefface toute instance active au-dessus de la nouvelle. Ainsi, il peut mettre fin à l'ancienne instance avant de terminer le processus.



1

Pas:

1) Ajoutez les autorisations requises dans le Manifest.xmlfichier.

<!--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) Créez un écouteur pour les changements d'état du téléphone.

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) Initialisez l'auditeur dans votre OnCreate

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

mais si vous souhaitez reprendre le dernier état de votre application ou la ramener de la pile arrière , remplacez-la FLAG_ACTIVITY_CLEAR_TOPparFLAG_ACTIVITY_SINGLE_TOP

Référencez cette réponse



0

Lorsque vous démarrez votre appel, ça a l'air bien.

Il y a une différence entre Android 11+ et down pour mettre votre application au premier plan.

Android 10 ou moins, vous devez démarrer une nouvelle intention, Android 11+ vous utilisez simplement BringTaskToFront

Dans l'état d'appel 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);
}

J'ai défini le MyActivity.MyActivityTaskIdlors de l'appel sur mon activité comme ceci, cela ne fonctionne pas, définissez cette variable sur la page d'activité parente de la page à laquelle vous souhaitez revenir.

MyActivity.MyActivityTaskId = this.getTaskId();

MyActivityTaskId est une variable statique sur ma classe d'activité

public static int MyActivityTaskId = 0;

J'espère que cela fonctionnera pour vous. J'utilise le code ci-dessus un peu différemment, j'ouvre mon application dès que l'appel est répondu pour que l'utilisateur puisse voir les détails de l'appelant.

J'ai également mis des trucs dans le AndroidManifest.xml:

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

et autorisations:

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

Veuillez poser des questions si ou quand vous êtes bloqué.

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.