Як здійснити телефонний дзвінок в android і повернутися до своєї діяльності, коли дзвінок виконано?


129

Я запускаю діяльність для здійснення телефонного дзвінка, але коли я натиснув кнопку "завершити дзвінок", вона не повертається до моєї діяльності. Скажіть, будь ласка, як я можу запустити активність дзвінка, яка повертається до мене після натискання кнопки "Закінчити дзвінок"? Ось як я телефоную:

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

Відповіді:


106

використовуйте PhoneStateListener, щоб побачити, коли виклик закінчується. вам, швидше за все, потрібно буде викликати дії слухача, щоб дочекатися початку дзвінка (дочекайтеся, коли його знову змінити з PHONE_STATE_OFFHOOK на PHONE_STATE_IDLE), а потім написати якийсь код, щоб повернути додаток до стану IDLE.

вам може знадобитися запустити слухача в сервісі, щоб переконатися, що він залишається в режимі роботи та перезапустить додаток. деякий приклад коду:

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

Визначення слухача:

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

У свій Manifest.xmlфайл додайте такий дозвіл:

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

10
Не забудьте дозвіл. ;)
Gp2mv3

5
Як зазначав Gp2mv3, не забудьте додати дозвіл READ_PHONE_STATE до AndroidManifest.xml.
Купер

6
@moonlightcheese Чи можете ви додати код, щоб повернутися в наш додаток із програми для дзвінків?
Geek

це небезпечно, оскільки воно завжди відкриватиме вашу активність у додатку щоразу, коли ви телефонуєте
user924

49

Це стосується питання, яке задає Starter.

Проблема з вашим кодом полягає в тому, що ви не передаєте номер належним чином.

Код повинен бути:

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

Не забудьте додати дозвіл у файл маніфесту.

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

або

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

для екстреної допомоги в разі DIALвикористовується.


7
Мені важко зрозуміти, як ваш код відрізняється від коду в оригінальному запитанні
Ілля Саункін

Код не відрізняється. Потрібно додати дозвіл у файл маніфесту.
Приа

4
android.permission.CALL_PRIVILEGED Дозвіл надається лише для системних додатків, недоступних на рівні додатків.
CoDe

і що це? він не повернеться до вашої активності
user924

24

У нас була така ж проблема, і нам вдалося її вирішити, використовуючи PhoneStateListenerідентифікувати, коли закінчується виклик, але крім того, ми повинні були виконати finish()початкову діяльність перед тим, як почати її знову startActivity, інакше журнал викликів буде перед нею.


4
можна уникнути цього, використовуючи інший метод. якщо ви створили ContentObserver, який дотримується журналу викликів андроїда, програма не запускатиметься, поки не буде внесена зміна журналу викликів. я фактично повинен був скинути PhoneStateListener на користь цієї моделі, оскільки моєму додатку потрібні дані журналу викликів, і слухач повертався до того, як ці зміни були внесені. pastebin.com/bq2s9EVa
moonlightcheese

11
@ André: ваше посилання, здається, порушено
агрегат1166877

Я би подарував вам мільйонну репутацію (якби мене було багато :)) Дякую за те, що я провів свій день!
keybee

1
Проблема з посиланнями я кажу!
Dheeraj Bhaskar

Інтернет-архів на допомогу ... web.archive.org/web/20120123224619/http://umamao.com/questions/…
Основний

13

Я знайшов EndCallListener найфункціональнішим прикладом, щоб отримати описану поведінку (закінчити (), викликати, перезапустити) Я додав декілька SharedPreferences, щоб слухач мав посилання на управління цією поведінкою.

Мій OnClick, ініціалізація та EndCallListener відповідають лише на дзвінки з програми. Інші дзвінки ігноруються.

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

        }

    }
}

додайте їх до 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>

і щось подібне у вашому Маніфесті, якщо вам потрібно повернутися до зовнішнього вигляду перед викликом

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

і помістіть їх у свою «мою активність»

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

використовуйте це, щоб ініціалізувати поведінку для свого onClick в моїй активності, наприклад, після 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();

}

Ви повинні виявити, що натискання списку номерів телефонів завершує вашу активність, здійснює дзвінок на номер та повертається до вашої активності, коли виклик закінчується.

Здійснення дзвінка за межами вашої програми, поки вона все ще знаходиться, не перезапустить вашу активність (якщо це не такий, як останній дзвонений номер BParty).

:)


5
Вибачте, але цей код виглядає дещо некрасиво. Дякую за відповідь, хоча
П'єр

7

ви можете використовувати startActivityForResult ()


1
Використовуючи android 5.0, метод onActivityResult викликає виклик негайно, виклик починається !!
Panciz

6

Це рішення з моєї точки зору:

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

    }

Звичайно, у визначенні Activity (class) ви повинні реалізувати View.OnClickListener.


6

Ось мій приклад: спочатку користувач отримує можливість записати номер, який він / вона хоче набрати, а потім натискає кнопку виклику і спрямовується на телефон. Після відміни дзвінка користувач надсилається назад до програми. Для цього кнопці в xml потрібен метод onClick ('makePhoneCall' у цьому прикладі). Вам також потрібно зареєструвати дозвіл у маніфесті.

Маніфест

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

Діяльність

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

ти навіть не те, про що ти говориш. READ_PHONE_STATE - ви не використовуєте його у своєму прикладі коду, чому ви додали його? звичайно, він поверне вас до своєї програми, якщо ви натиснете кнопку скасування, але автор запитав про те, як повернутися до активності після прийняття дзвінка
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

Якщо ви збираєтеся використовувати слухача, вам потрібно буде додати цей дозвіл і в маніфест.

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

3

Всередині PhoneStateListener після того, як побачення завершено, краще скористайтеся:

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

Де CallDispatcherActivity - це діяльність, коли користувач зателефонував (у моєму випадку диспетчеру служби таксі). Це просто видаляє додаток Android телефонії зверху, користувач повертається замість некрасивого коду, який я бачив тут.


1
І не забудьте видалити слухача після телефонного дзвінка так:((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE);
Дмитро Новіков,

Я намагався використовувати ваш підхід, але активність (звана ControlPanel) не активується. На дисплеї продовжує відображатися інтерфейс набору номера телефону, а реєстратори в режимі вводу on-Resume та onNewIntent в ControlPanel повністю безшумні. Ось мета: Intent intentRestart = new Intent(ControlPanel.this, ControlPanel.class);. Я повинен зазначити, що PhoneStateListener також знаходиться в ControlPanel. Тобто, моя мета - повернути інтерфейс користувача в стан, в якому він був до початку телефонного дзвінка. Будь-які пропозиції?
PeteH

Спробуйте ввійти всередині своєї програми PhoneStateListener.
Дмитро Новіков

3

Щоб повернутися до свого Activity, вам потрібно буде послухати TelephonyStates. Після цього listenerви можете надіслати Intentповторне відкриття свого Activityтелефону в режимі очікування.

Принаймні ось як я це зроблю.


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

Спробуйте скористатися:

finish();

в кінці діяльності. Це перенаправить вас на вашу попередню діяльність.


2

При PhoneStateListenerвикористанні потрібно переконатися, що PHONE_STATE_IDLEпісля PHONE_STATE_OFFHOOKзапуску дії, яка повинна бути виконана після дзвінка, використовується наступний a . Якщо тригер з’явиться, побачивши PHONE_STATE_IDLE, ви зробите це перед викликом. Тому що ви побачите зміну штатуPHONE_STATE_IDLE -> PHONE_STATE_OFFHOOK -> PHONE_STATE_IDLE.


чи не можливо додаток припиняється, коли відкривається екран, що триває?
lisovaccaro

Об'єкт слухача, щойно встановлений для прослуховування TelephonyManager ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(new PhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE), продовжить слухати стан телефону та буде активним, поки явно не зупиниться з((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE)
PonMaran

2

// в setonclicklistener поставити цей код:

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

// надати дозвіл на дзвінок у маніфесті:

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

1

@Dmitri Novikov, FLAG_ACTIVITY_CLEAR_TOPвидаляє будь-який активний екземпляр поверх нового. Отже, він може закінчити старий екземпляр до того, як він завершить процес.



1

Кроки:

1) Додайте необхідні дозволи у Manifest.xmlфайл.

<!--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) Створіть слухач для зміни стану телефону.

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) Ініціалізуйте слухача у своєму OnCreate

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

але якщо ви хочете відновити свою програму в останньому стані або повернути її із заднього стеку , замініть FLAG_ACTIVITY_CLEAR_TOPнаFLAG_ACTIVITY_SINGLE_TOP

Посилайтеся на цю відповідь



0

Починаючи дзвінок, це виглядає чудово.

Існує різниця між Android 11+ і нижче в тому, що ви приводите свою програму на фронт.

Android 10 або менше вам потрібно запустити новий намір, а Android 11+ ви просто використовуєте BringTaskToFront

У режимі виклику 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);
}

Я встановлюю так, щоб MyActivity.MyActivityTaskIdздійснити дзвінок у своїй діяльності так, це не працює, встановив цю змінну на батьківській сторінці активності сторінки, на яку ви хочете повернутися.

MyActivity.MyActivityTaskId = this.getTaskId();

MyActivityTaskId - статична змінна для мого класу активності

public static int MyActivityTaskId = 0;

Я сподіваюся, що це допоможе вам. Я використовую вищезгаданий код трохи інакше, я відкриваю свою програму, як тільки відповідь на дзвінок, щоб користувач міг бачити деталі абонента.

Я також встановив кілька речей AndroidManifest.xml:

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

та дозволи:

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

Будь ласка, задайте питання, якщо або коли ви застрягли.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.