如何在android中拨打电话并完成通话后返回我的活动?


129

我正在启动一个活动来打电话,但是当我按下“结束通话”按钮时,它不会返回到我的活动。您能告诉我如何启动按下“结束通话”按钮时返回的通话活动吗?这是我拨打电话的方式:

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

Answers:


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

5
正如Gp2mv3所指出的,不要忘记将READ_PHONE_STATE权限添加到AndroidManifest.xml。
库珀

6
@moonlightcheese您可以添加代码以从通话应用返回到我们的应用吗?
极客

这很危险,因为它每次调用时都会始终打开您的应用程序活动
user924'4

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
我很难看到您的代码与原始问题中的代码有何不同
Elijah Saounkine 2011年

代码没有不同。您需要在清单文件中添加权限。
普里亚(Pria)2012年

4
android.permission.CALL_PRIVILEGED权限仅授予在应用程序级别不可用的系统应用程序。
CoDe 2014年

那是什么 它不会返回您的活动
user924'4

24

我们遇到了同样的问题,并设法通过使用a PhoneStateListener来识别呼叫结束的时间来解决该问题,但是此外,finish()在再次使用再次开始之前,我们不得不进行原始活动startActivity,否则,呼叫日志将位于它的前面。


4
您可以使用其他方法避免这种情况。如果您构建一个观察android通话记录的ContentObserver,则只有在更改通话记录后,该应用才会启动。实际上,我必须转储PhoneStateListener以支持此模型,因为我的应用程序需要调用日志数据,并且在进行这些更改之前,侦听器正在返回。 pastebin.com/bq2s9EVa
moonlightcheese

11
@安德烈:你的链接似乎被打破
aggregate116​​6877

我会给你一百万的声誉(如果我有很多的话:))感谢您度过美好的一天!
keybee

1
我说的链接问题!
Dheeraj Bhaskar 2014年


13

我发现EndCallListener是功能最强大的示例,为了获得所描述的行为(finish(),调用,重新启动),我添加了一些SharedPreferences,因此Listener具有管理此行为的引用。

我的OnClick,initialize和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()

用它来初始化您在myActivity中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(类)定义中,您必须实现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 '18

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);
Dmitri Novikov 2012年

我尝试使用您的方法,但是未重新激活活动(称为ControlPanel)。显示屏继续显示电话拨号程序界面,并且ControlPanel中onResume和onNewIntent入口点上的记录器完全静音。目的是:Intent intentRestart = new Intent(ControlPanel.this, ControlPanel.class);。我应该指出,PhoneStateListener也在ControlPanel中。即,我的目标是将UI恢复到发起电话之前的状态。有什么建议?
PeteH 2013年

尝试在PhoneStateListener实现内部记录日志。
Dmitri Novikov

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用来触发调用后要做的动作。如果触发是在看到时发生的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_TOPFLAG_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" />

请问是否或何时卡住。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.