Wie kann ich in Android telefonieren und nach Abschluss des Anrufs zu meiner Aktivität zurückkehren?

129

Ich starte eine Aktivität, um einen Anruf zu tätigen, aber wenn ich die Taste "Anruf beenden" drückte, wird nicht zu meiner Aktivität zurückgekehrt. Können Sie mir bitte sagen, wie ich eine Anrufaktivität starten kann, die auf mich zurückkommt, wenn die Schaltfläche "Anruf beenden" gedrückt wird? So telefoniere ich:

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

Antworten:

106

Verwenden Sie einen PhoneStateListener, um zu sehen, wann der Anruf beendet wird. Sie müssen höchstwahrscheinlich die Listener-Aktionen auslösen, um auf den Start des Aufrufs zu warten (warten Sie, bis der Wechsel von PHONE_STATE_OFFHOOK zu PHONE_STATE_IDLE erneut erfolgt) und dann Code schreiben, um Ihre App wieder in den IDLE-Status zu versetzen.

Möglicherweise müssen Sie den Listener in einem Dienst ausführen, um sicherzustellen, dass er aktiv bleibt und Ihre App neu gestartet wird. ein Beispielcode:

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

Hörerdefinition:

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

Fügen Sie Ihrer Manifest.xmlDatei die folgende Berechtigung hinzu:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
Mondscheinkäse
quelle
10
Vergiss die Erlaubnis nicht. ;)
Gp2mv3
5
Vergessen Sie nicht, wie Gp2mv3 bemerkt hat, die Berechtigung READ_PHONE_STATE zur Datei AndroidManifest.xml hinzuzufügen.
Cooper
6
@moonlightcheese Können Sie Code hinzufügen, um von der Anruf-App zu unserer App zurückzukehren?
Geek
Dies ist gefährlich, da es Ihre App-Aktivität jedes Mal
öffnet,
49

Dies betrifft die von Starter gestellte Frage.

Das Problem mit Ihrem Code ist, dass Sie die Nummer nicht richtig übergeben.

Der Code sollte sein:

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

Vergessen Sie nicht, die Berechtigung in die Manifestdatei aufzunehmen.

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

oder

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

für Notrufnummer falls DIALverwendet.

Pria
quelle
7
Es fällt mir schwer zu sehen, wie sich Ihr Code von dem Code in der ursprünglichen Frage unterscheidet
Elijah Saounkine
Der Code ist nicht anders. Sie müssen die Berechtigung in die Manifestdatei einfügen.
Pria
4
android.permission.CALL_PRIVILEGED Die Berechtigung wird nur für System-Apps erteilt, die auf App-Ebene nicht verfügbar sind.
CoDe
und was ist das? es wird nicht zu Ihrer Aktivität zurückkehren
user924
24

Wir hatten das gleiche Problem und konnten es lösen, indem PhoneStateListenerwir a verwendeten , um zu identifizieren, wann der Anruf endet, aber zusätzlich mussten wir finish()die ursprüngliche Aktivität ausführen, bevor wir sie erneut starteten startActivity, da sich sonst das Anrufprotokoll davor befand.

André Lima
quelle
4
Sie können dies vermeiden, indem Sie eine andere Methode verwenden. Wenn Sie einen ContentObserver erstellen, der das Android-Anrufprotokoll überwacht, wird die App erst gestartet, wenn die Änderung des Anrufprotokolls vorgenommen wurde. Ich musste den PhoneStateListener tatsächlich zugunsten dieses Modells ausgeben, da meine App Anrufprotokolldaten benötigte und der Listener zurückkehrte, bevor diese Änderungen vorgenommen wurden. pastebin.com/bq2s9EVa
moonlightcheese
11
@ André: Ihr Link scheint defekt zu sein
aggregat1166877
Ich würde dir eine Million Ruf geben (wenn ich viel hätte :)) Danke, dass du meinen Tag gemacht hast!
Keybee
1
Das Problem mit Links sage ich!
Dheeraj Bhaskar
13

Ich fand den EndCallListener das funktionalste Beispiel. Um das beschriebene Verhalten zu erhalten (finish (), call, restart), habe ich einige SharedPreferences hinzugefügt, damit der Listener einen Verweis zum Verwalten dieses Verhaltens hatte.

Mein OnClick, Initialisieren und EndCallListener antworten nur auf Anrufe von der App. Andere Anrufe werden ignoriert.

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

        }

    }
}

Fügen Sie diese zu strings.xml hinzu

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

und so etwas in Ihrem Manifest, wenn Sie vor dem Anruf zum Erscheinungsbild zurückkehren müssen

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

und füge diese in deine 'myActivity' ein

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

Verwenden Sie diese Option, um das Verhalten für Ihren onClick in myActivity zu initiieren, z. B. nach 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();

}

Sie sollten feststellen, dass das Klicken auf Ihre Telefonnummernliste Ihre Aktivität beendet, die Nummer anruft und nach Beendigung des Anrufs zu Ihrer Aktivität zurückkehrt.

Wenn Sie einen Anruf von außerhalb Ihrer App tätigen, während diese noch verfügbar ist, wird Ihre Aktivität nicht neu gestartet (es sei denn, sie entspricht der zuletzt angerufenen BParty-Nummer).

:) :)

TheSolarSheriff
quelle
5
Entschuldigung, aber dieser Code sieht etwas hässlich aus. Vielen Dank für die Antwort
Pierre
7

Sie können startActivityForResult () verwenden

Yakr
quelle
1
Unter Android 5.0 wird die onActivityResult-Methode sofort aufgerufen, wenn der Aufruf beginnt !!
Panciz
6

Dies ist aus meiner Sicht eine Lösung:

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

    }

Natürlich müssen Sie in der Definition der Aktivität (Klasse) View.OnClickListener implementieren.

Cikabole
quelle
6

Hier ist mein Beispiel: Zuerst muss der Benutzer die Nummer eingeben, die er wählen möchte, und dann eine Anruftaste drücken und zum Telefon geleitet werden. Nach dem Abbrechen des Anrufs wird der Benutzer an die Anwendung zurückgesendet. Dazu muss die Schaltfläche eine onClick-Methode (in diesem Beispiel 'makePhoneCall') in der XML-Datei haben. Sie müssen die Berechtigung auch im Manifest registrieren.

Manifest

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

Aktivität

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" />
Oyee
quelle
Sie wissen nicht einmal, wovon Sie sprechen. READ_PHONE_STATE - Sie verwenden es nicht in Ihrem Beispielcode. Warum haben Sie es hinzugefügt? Natürlich kehren Sie zu Ihrer App-Aktivität zurück, wenn Sie auf die Schaltfläche "
Abbrechen" klicken. Der
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);
}
Laxman Bhattarai
quelle
5

Wenn Sie einen Listener verwenden möchten, müssen Sie diese Berechtigung auch dem Manifest hinzufügen.

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

In PhoneStateListener nach Beendigung des Anrufs besser nutzen:

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

Wobei CallDispatcherActivity die Aktivität ist, bei der der Benutzer einen Anruf gestartet hat (in meinem Fall an einen Taxidienst-Dispatcher). Dadurch wird nur die Android-Telefonie-App von oben entfernt. Der Benutzer erhält statt des hässlichen Codes, den ich hier gesehen habe, zurück.

Dmitri Novikov
quelle
1
Und vergessen Sie nicht, den Listener nach dem Telefonat wie folgt zu entfernen:((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE);
Dmitri Novikov
Ich habe versucht, Ihren Ansatz zu verwenden, aber die Aktivität (ControlPanel genannt) wird nicht reaktiviert. Das Display zeigt weiterhin die Telefonwahloberfläche an, und die Protokollierer an den Einstiegspunkten onResume und onNewIntent in ControlPanel sind vollständig stumm. Hier ist die Absicht : Intent intentRestart = new Intent(ControlPanel.this, ControlPanel.class);. Ich sollte darauf hinweisen, dass sich der PhoneStateListener auch in ControlPanel befindet. Das heißt, mein Ziel ist es, die Benutzeroberfläche auf den Zustand zurückzusetzen, in dem sie sich vor dem Einleiten des Telefonanrufs befand. Irgendwelche Vorschläge?
PeteH
Versuchen Sie, sich in Ihrer PhoneStateListener-Implementierung anzumelden.
Dmitri Novikov
3

Um zu Ihrem zurückzukehren Activity, müssen Sie zuhören TelephonyStates. Daraufhin listenerkönnen Sie eine senden Intent, um Ihr ActivityTelefon wieder zu öffnen, sobald das Telefon inaktiv ist.

Zumindest werde ich das so machen.

Aimeric
quelle
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" />          
ritesh4326
quelle
2

Versuchen Sie es mit:

finish();

am Ende der Aktivität. Sie werden zu Ihrer vorherigen Aktivität weitergeleitet.

Ankit Kedia
quelle
2

Wenn PhoneStateListeneres verwendet wird, muss sichergestellt werden, dass das PHONE_STATE_IDLEfolgende a PHONE_STATE_OFFHOOKverwendet wird, um die nach dem Aufruf auszuführende Aktion auszulösen. Wenn der Auslöser beim Sehen auftritt PHONE_STATE_IDLE, werden Sie ihn am Ende vor dem Anruf ausführen. Weil Sie sehen werden, wie sich der Zustand ändertPHONE_STATE_IDLE -> PHONE_STATE_OFFHOOK -> PHONE_STATE_IDLE.

PonMaran
quelle
Ist es nicht möglich, dass die App stoppt, wenn der Bildschirm für laufende Anrufe geöffnet wird?
Lisovaccaro
Das Listener-Objekt, das einmal zum Abhören des TelephonyManager eingestellt wurde, hört ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(new PhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE)weiterhin den Telefonstatus ab und ist aktiv, bis es explizit mit((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE)
PonMaran
2

// in setonclicklistener diesen Code einfügen:

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

// Erlaubnis zum Aufruf im Manifest geben:

<uses-permission android:name="android.permission.CALL_PHONE"></uses-permission>
Hiren Patel
quelle
1

@Dmitri Novikov, FLAG_ACTIVITY_CLEAR_TOPlöscht alle aktiven Instanzen über der neuen. Daher kann die alte Instanz beendet werden, bevor der Vorgang abgeschlossen ist.

PonMaran
quelle
1

Fügen Sie hinzu, dies ist Ihre XML: android:autoLink="phone"

Roman Marius
quelle
2
Bitte erläutern Sie. "Welche XML"?
Anas Azeem
1

Schritte:

1) Fügen Sie die erforderlichen Berechtigungen in die Manifest.xmlDatei ein.

<!--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) Erstellen Sie einen Listener für die Änderungen des Telefonstatus.

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) Initialisieren Sie den Listener in Ihrem OnCreate

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

aber wenn Sie Ihre Anwendung letzten Zustand fortsetzen möchten oder es von der Rückseite Stapel zurück zu bringen , dann ersetzen FLAG_ACTIVITY_CLEAR_TOPmitFLAG_ACTIVITY_SINGLE_TOP

Verweisen Sie auf diese Antwort

Sami El-Tamawy
quelle
0

Wenn Sie Ihren Anruf starten, sieht es gut aus.

Es gibt jedoch einen Unterschied zwischen Android 11+ und Down, wenn es darum geht, Ihre App in den Vordergrund zu rücken.

Android 10 oder weniger müssen Sie eine neue Absicht starten, Android 11+ verwenden Sie einfach BringTaskToFront

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

Ich habe die MyActivity.MyActivityTaskIdVariable beim Aufrufen meiner Aktivität so festgelegt, dass dies nicht funktioniert. Diese Variable wird auf der übergeordneten Aktivitätsseite der Seite festgelegt, zu der Sie zurückkehren möchten.

MyActivity.MyActivityTaskId = this.getTaskId();

MyActivityTaskId ist eine statische Variable in meiner Aktivitätsklasse

public static int MyActivityTaskId = 0;

Ich hoffe das wird für dich funktionieren. Ich verwende den obigen Code etwas anders. Ich öffne meine App, sobald der Anruf beantwortet wurde, damit der Benutzer die Details des Anrufers sehen kann.

Ich habe auch ein paar Sachen in die gesetzt AndroidManifest.xml:

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

und Berechtigungen:

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

Bitte stellen Sie Fragen, wenn Sie stecken bleiben.

Pierre
quelle