Jak wykonać telefon na Androidzie i wrócić do aktywności po zakończeniu rozmowy?

129

Uruchamiam działanie, aby wykonać połączenie telefoniczne, ale po naciśnięciu przycisku „Zakończ połączenie” nie wraca do mojej aktywności. Czy możesz mi powiedzieć, jak mogę uruchomić połączenie, które wraca do mnie po naciśnięciu przycisku „Zakończ połączenie”? Oto jak dzwonię:

    String url = "tel:3334444";
    Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
hap497
źródło

Odpowiedzi:

106

użyj PhoneStateListener, aby zobaczyć, kiedy połączenie jest zakończone. najprawdopodobniej będziesz musiał wyzwolić akcje słuchacza, aby zaczekały na rozpoczęcie połączenia (poczekaj, aż ponownie zmieni się z PHONE_STATE_OFFHOOK na PHONE_STATE_IDLE), a następnie napisz kod, aby przywrócić aplikację do stanu bezczynności.

może być konieczne uruchomienie odbiornika w usłudze, aby upewnić się, że działa, a aplikacja jest ponownie uruchamiana. przykładowy kod:

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

Definicja słuchacza:

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

W swoim Manifest.xmlpliku dodaj następujące uprawnienia:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
sera księżycowego
źródło
10
Nie zapomnij o pozwoleniu. ;)
Gp2mv3
5
Jak zauważył Gp2mv3, nie zapomnij dodać uprawnienia READ_PHONE_STATE do pliku AndroidManifest.xml.
Cooper
6
@moonlightcheese Czy możesz dodać kod, aby wrócić do naszej aplikacji z aplikacji call?
Geek
jest to niebezpieczne, ponieważ zawsze powoduje otwarcie Twojej aktywności w aplikacji za każdym razem, gdy zadzwonisz
user924,
49

Chodzi o pytanie zadane przez Startera.

Problem z Twoim kodem polega na tym, że nie przekazujesz numeru poprawnie.

Kod powinien wyglądać następująco:

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

Nie zapomnij dodać uprawnienia w pliku manifestu.

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

lub

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

na numer alarmowy w przypadku, gdy DIALjest używany.

Pria
źródło
7
Trudno mi zobaczyć, jak twój kod różni się od kodu z pierwotnego pytania
Elijah Saounkine.
Kod nie jest inny. Musisz dodać uprawnienia w pliku manifestu.
Pria
4
android.permission.CALL_PRIVILEGED Uprawnienie jest przyznawane tylko aplikacjom systemowym niedostępnym na poziomie aplikacji.
CoDe
I co to jest? nie wróci do Twojej aktywności
user924
25

Mieliśmy ten sam problem i udało nam się go rozwiązać, używając a PhoneStateListenerdo identyfikacji zakończenia połączenia, ale dodatkowo musieliśmy wykonać finish()pierwotną czynność przed jej ponownym uruchomieniem startActivity, w przeciwnym razie dziennik połączeń znajdowałby się przed nim.

André Lima
źródło
5
Możesz tego uniknąć, używając innej metody. Jeśli utworzysz ContentObserver, który obserwuje dziennik połączeń systemu Android, aplikacja nie zostanie uruchomiona, dopóki nie zostanie wprowadzona zmiana dziennika połączeń. W rzeczywistości musiałem zrzucić PhoneStateListener na rzecz tego modelu, ponieważ moja aplikacja potrzebowała danych dziennika połączeń, a odbiornik wracał przed wprowadzeniem tych zmian. pastebin.com/bq2s9EVa
moonlightcheese
11
@ André: Twój link wygląda na uszkodzony
agregat1166877
Dałbym Ci milion reputacji (gdybym miał dużo :)) Dziękuję, że umiliłeś mi dzień!
keybee
1
Problem z linkami mówię!
Dheeraj Bhaskar
Archiwum internetowe na ratunek ... web.archive.org/web/20120123224619/http://umamao.com/questions/
Podstawowy
13

Znalazłem EndCallListener jako najbardziej funkcjonalny przykład, aby uzyskać opisane zachowanie (finish (), call, restart) Dodałem kilka SharedPreferences, aby Listener miał odniesienie do zarządzania tym zachowaniem.

My OnClick, inicjalizacja i EndCallListener odpowiadają tylko na połączenia z aplikacji. Inne połączenia zostały zignorowane.

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

        }

    }
}

dodaj je do 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>

i coś takiego w swoim Manifeście, jeśli chcesz wrócić do wyglądu i stylu sprzed rozmowy

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

i umieść je w swojej „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()

użyj tego do zainicjowania zachowania swojego onClick w myActivity, np. po 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();

}

Powinieneś zauważyć, że kliknięcie listy numerów telefonów kończy Twoją działalność, powoduje połączenie z numerem i powrót do Twojej aktywności po zakończeniu połączenia.

Wykonywanie połączenia spoza aplikacji, gdy jest ona nadal w pobliżu, nie spowoduje ponownego uruchomienia Twojej działalności (chyba że jest to ten sam numer, z którym dzwoniono ostatnio).

:)

TheSolarSheriff
źródło
5
Przepraszamy, ale ten kod wygląda trochę brzydko. Jednak dzięki za odpowiedź
Pierre
7

możesz użyć startActivityForResult ()

yakr
źródło
1
Korzystając z Androida 5.0, metoda onActivityResult jest wywoływana natychmiastowo!
Panciz,
6

To jest rozwiązanie z mojego punktu widzenia:

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

    }

Oczywiście w definicji Activity (class) musisz zaimplementować View.OnClickListener.

cikabole
źródło
6

Oto mój przykład: najpierw użytkownik wpisuje numer, który chce wybrać, a następnie naciska przycisk połączenia i zostaje przekierowany do telefonu. Po anulowaniu połączenia użytkownik zostaje odesłany z powrotem do aplikacji. W tym celu przycisk musi mieć metodę onClick (w tym przykładzie „makePhoneCall”) w pliku xml. Musisz również zarejestrować pozwolenie w manifeście.

Oczywisty

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

Czynność

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
źródło
nie masz nawet tego, o czym mówisz. READ_PHONE_STATE - nie używasz go w przykładowym kodzie, dlaczego go dodałeś? oczywiście po naciśnięciu przycisku anulowania nastąpi powrót do aktywności w aplikacji, ale autor pytania o to, jak wrócić do aktywności po zaakceptowaniu połączenia
użytkownik924
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
źródło
5

Jeśli zamierzasz używać listenera, musisz dodać to uprawnienie również do manifestu.

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
martincm
źródło
3

Wewnątrz PhoneStateListener po obejrzeniu połączenia lepiej użyj:

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

Gdzie CallDispatcherActivity jest działaniem, w którym użytkownik uruchomił połączenie (w moim przypadku do dyspozytora taksówek). To tylko usuwa aplikację telefoniczną na Androida z góry, użytkownik wraca zamiast brzydkiego kodu, który tutaj widziałem.

Dmitri Novikov
źródło
1
I nie zapomnij usunąć słuchacza po zakończeniu rozmowy telefonicznej, na przykład:((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE);
Dmitri Novikov
Próbowałem użyć twojego podejścia, ale aktywność (o nazwie ControlPanel) nie jest reaktywowana. Wyświetlacz nadal pokazuje interfejs dialera telefonu, a rejestratory w punktach wejściowych onResume i onNewIntent w ControlPanel są całkowicie ciche. Oto intencją: Intent intentRestart = new Intent(ControlPanel.this, ControlPanel.class);. Powinienem zaznaczyć, że PhoneStateListener również znajduje się w ControlPanel. To znaczy, moim celem jest przywrócenie interfejsu użytkownika do stanu, w jakim znajdował się przed zainicjowaniem połączenia telefonicznego. Jakieś sugestie?
PeteH
Spróbuj zalogować się w implementacji PhoneStateListener.
Dmitri Novikov
3

Aby wrócić do swojego Activity, musisz posłuchać TelephonyStates. Na który listenermożna wysłać Intentdo ponownego uruchomienia Activity, gdy telefon jest w stanie bezczynności.

Przynajmniej tak to zrobię.

Aimeric
źródło
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
źródło
2

Spróbuj użyć:

finish();

pod koniec działania. Przekieruje Cię do poprzedniej aktywności.

Ankit Kedia
źródło
2

Kiedy PhoneStateListenerjest używane, należy upewnić się, że PHONE_STATE_IDLEpo a PHONE_STATE_OFFHOOKjest używane do wyzwalania akcji, która ma zostać wykonana po wywołaniu. Jeśli wyzwolenie nastąpi po zobaczeniu PHONE_STATE_IDLE, skończysz robiąc to przed wezwaniem. Ponieważ zobaczysz zmianę stanuPHONE_STATE_IDLE -> PHONE_STATE_OFFHOOK -> PHONE_STATE_IDLE.

PonMaran
źródło
czy nie jest możliwe, że aplikacja zatrzymuje się, gdy otwiera się ekran trwającego połączenia?
lisovaccaro
Obiekt Listener po ustawieniu nasłuchiwania TelephonyManager ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(new PhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE)będzie nadal nasłuchiwał stanu telefonu i będzie aktywny, dopóki nie zostanie wyraźnie zatrzymany((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE)
PonMaran
2

// w setonclicklistener umieść ten kod:

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

// daj pozwolenie na wywołanie w manifeście:

<uses-permission android:name="android.permission.CALL_PHONE"></uses-permission>
Hiren Patel
źródło
1

@Dmitri Novikov, FLAG_ACTIVITY_CLEAR_TOPczyści każdą aktywną instancję na nowej. Może więc zakończyć starą instancję, zanim zakończy proces.

PonMaran
źródło
1

Dodaj to jest twój xml: android:autoLink="phone"

Roman Marius
źródło
2
Proszę rozwinąć. „Który plik XML”?
Anas Azeem
1

Kroki:

1) Dodaj wymagane uprawnienia w Manifest.xmlpliku.

<!--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) Utwórz nasłuchiwanie zmian stanu telefonu.

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) Zainicjuj odbiornik w swoim OnCreate

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

ale jeśli chcesz, aby wznowić swoją aplikację ostatni stan lub przynieść go ze stosu z powrotem , a następnie zastąpić FLAG_ACTIVITY_CLEAR_TOPzFLAG_ACTIVITY_SINGLE_TOP

Odwołaj się do tej odpowiedzi

Sami El-Tamawy
źródło
1
   Intent callIntent = new Intent(Intent.ACTION_CALL);
   callIntent .setData(Uri.parse("tel:+91-XXXXXXXXX"));
   startActivity(callIntent );
Dhina k
źródło
0

Kiedy zaczynasz rozmowę, wygląda dobrze.

Istnieje jednak różnica między Androidem 11+ a downem w przenoszeniu aplikacji na pierwszy plan.

Android 10 lub mniej musisz zacząć od nowa, Android 11+ po prostu używasz BringTaskToFront

W stanie połączenia 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);
}

Ustawiam MyActivity.MyActivityTaskIdwywołanie mojej aktywności w ten sposób, jeśli to nie działa, ustawiam tę zmienną na stronie aktywności nadrzędnej strony, do której chcesz wrócić.

MyActivity.MyActivityTaskId = this.getTaskId();

MyActivityTaskId jest zmienną statyczną w mojej klasie aktywności

public static int MyActivityTaskId = 0;

Mam nadzieję, że to zadziała. Używam powyższego kodu nieco inaczej, otwieram aplikację, gdy tylko odbierze połączenie, aby użytkownik mógł zobaczyć szczegóły dzwoniącego.

W tym też umieściłem kilka rzeczy AndroidManifest.xml:

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

i uprawnienia:

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

Proszę zadawać pytania, jeśli lub kiedy utkniesz.

Pierre
źródło