Как позвонить в android и вернуться к своей деятельности, когда звонок будет сделан?

129

Я запускаю действие для выполнения телефонного звонка, но когда я нажимаю кнопку «Завершить вызов», оно не возвращается к моей активности. Подскажите, пожалуйста, как мне запустить действие вызова, которое возвращается ко мне при нажатии кнопки «Завершить вызов»? Вот как я звоню по телефону:

    String url = "tel:3334444";
    Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
hap497
источник

Ответы:

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"/>
Moonlightcheese
источник
10
Не забывайте разрешение. ;)
Gp2mv3
5
Как отметил Gp2mv3, не забудьте добавить разрешение READ_PHONE_STATE в AndroidManifest.xml.
Cooper
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.

Pria
источник
7
Мне трудно понять, чем ваш код отличается от кода в исходном вопросе
Элайджа Саункин,
Код не отличается. Вам необходимо добавить разрешение в файл манифеста.
Pria
4
android.permission.CALL_PRIVILEGED Разрешение предоставляется только системным приложениям, недоступным на уровне приложения.
CoDe 02
и что это? он не вернется к вашей активности
user924
24

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

Андре Лима
источник
4
вы можете избежать этого, используя другой метод. Если вы создаете ContentObserver, который наблюдает за журналом вызовов Android, приложение не запустится, пока не будет выполнено изменение журнала вызовов. Мне фактически пришлось отказаться от PhoneStateListener в пользу этой модели, так как моему приложению нужны данные журнала вызовов, а прослушиватель возвращался до того, как были внесены эти изменения. pastebin.com/bq2s9EVa
moonlightcheese
11
@ André: похоже, ваша ссылка не работает
aggregate1166877
Я бы дал вам миллион репутации (если бы у меня было много :)) Спасибо, что сделали мой день!
keybee
1
Проблема со ссылками говорю!
Дирадж Бхаскар,
Интернет-архив спешит на помощь ... web.archive.org/web/20120123224619/http://umamao.com/questions/…
Basic
13

Я нашел EndCallListener наиболее функциональным примером, чтобы получить описанное поведение (finish (), call, restart), я добавил несколько SharedPreferences, чтобы у Listener была ссылка для управления этим поведением.

Мои OnClick, initialise и 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>

и поместите их в свой "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()

используйте это, чтобы инициировать поведение вашего onClick в myActivity, например, после 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).

:)

TheSolarSheriff
источник
5
Извините, но этот код выглядит некрасиво. Спасибо за ответ
Пьер
7

вы можете использовать startActivityForResult ()

yakr
источник
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 (класса) вы должны реализовать View.OnClickListener.

cikabole
источник
6

Вот мой пример: сначала пользователь набирает номер, который хочет набрать, а затем нажимает кнопку вызова и перенаправляется на телефон. После отмены звонка пользователь возвращается в приложение. Для этого кнопка должна иметь метод onClick (в данном примере «makePhoneCall») в xml. Вам также необходимо зарегистрировать разрешение в манифесте.

манифест

<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" />
оборота Oyee
источник
вы даже не понимаете, о чем говорите. 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);
}
Laxman Bhattarai
источник
5

Если вы собираетесь использовать слушателя, вам также необходимо добавить это разрешение в манифест.

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
martincm
источник
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) не активируется повторно. На дисплее по-прежнему отображается интерфейс программы набора номера, а средства ведения журнала в точках входа onResume и onNewIntent в ControlPanel полностью молчат. Вот цель: Intent intentRestart = new Intent(ControlPanel.this, ControlPanel.class);. Я должен указать, что PhoneStateListener также находится в ControlPanel. Т.е. моя цель - восстановить пользовательский интерфейс до того состояния, в котором он был до совершения телефонного звонка. Какие-либо предложения?
PeteH
Попробуйте войти в свою реализацию PhoneStateListener.
Дмитрий Новиков
3

Чтобы вернуться к своему Activity, вам нужно будет послушать TelephonyStates. На этом listenerвы можете отправить, Intentчтобы снова открыть ваш Activityтелефон, когда он не используется.

По крайней мере, так я и сделаю.

Aimeric
источник
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
источник
2

Попробуйте использовать:

finish();

в конце деятельности. Это перенаправит вас к вашей предыдущей деятельности.

Ankit Kedia
источник
2

Когда PhoneStateListenerиспользуется, необходимо убедиться, что PHONE_STATE_IDLEследующее PHONE_STATE_OFFHOOKиспользуется для запуска действия, которое будет выполнено после вызова. Если триггер PHONE_STATE_IDLEсработает после просмотра , вы сделаете это до звонка. Потому что вы увидите изменение состоянияPHONE_STATE_IDLE -> PHONE_STATE_OFFHOOK -> PHONE_STATE_IDLE.

PonMaran
источник
разве приложение не останавливается, когда открывается экран текущего вызова?
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очищает любой активный экземпляр поверх нового. Таким образом, он может завершить старый экземпляр до того, как завершит процесс.

PonMaran
источник
1

Добавьте это ваш xml: android:autoLink="phone"

Роман Мариус
источник
2
Пожалуйста, дополните. "Какой xml"?
Анас Азим
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" />

Пожалуйста, задавайте вопросы, если или когда вы застряли.

пьер
источник