Làm thế nào để thực hiện cuộc gọi điện thoại trong Android và quay lại hoạt động của tôi khi cuộc gọi được thực hiện?


129

Tôi đang khởi chạy một hoạt động để thực hiện cuộc gọi điện thoại, nhưng khi tôi nhấn nút 'kết thúc cuộc gọi', nó không quay trở lại hoạt động của tôi. Bạn có thể vui lòng cho tôi biết làm cách nào tôi có thể khởi chạy một hoạt động cuộc gọi quay lại với tôi khi nhấn nút 'Kết thúc cuộc gọi' không? Đây là cách tôi thực hiện cuộc gọi điện thoại:

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

Câu trả lời:


106

sử dụng PhoneStateListener để xem khi nào cuộc gọi kết thúc. rất có thể bạn sẽ cần kích hoạt các hành động của người nghe để chờ cuộc gọi bắt đầu (đợi cho đến khi thay đổi từ PHONE_STATE_OFFHOOK thành PHONE_STATE_IDLE một lần nữa) và sau đó viết một số mã để đưa ứng dụng của bạn trở lại trạng thái IDLE.

bạn có thể cần chạy trình nghe trong một dịch vụ để đảm bảo nó luôn hoạt động và ứng dụng của bạn được khởi động lại. một số mã ví dụ:

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

Định nghĩa người nghe:

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

Trong Manifest.xmltệp của bạn thêm quyền sau:

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

10
Đừng quên sự cho phép. ;)
Gp2mv3

5
Như Gp2mv3 đã lưu ý, đừng quên thêm quyền READ_PHONE_STATE vào AndroidManifest.xml.
Cooper

6
@moonlightcheese Bạn có thể thêm mã để quay lại ứng dụng của chúng tôi từ ứng dụng cuộc gọi không?
Geek

Điều này rất nguy hiểm vì nó sẽ luôn mở hoạt động ứng dụng của bạn mỗi khi bạn gọi
user924

49

Điều này liên quan đến câu hỏi của Starter.

Vấn đề với mã của bạn là bạn không chuyển đúng số.

Mã phải là:

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

Đừng quên thêm quyền trong tệp kê khai.

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

hoặc là

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

cho số khẩn cấp trong trường hợp DIALđược sử dụng.


7
Tôi đang gặp khó khăn để xem mã của bạn khác với mã trong câu hỏi ban đầu như thế nào
Elijah Saounkine

Mã không khác nhau. Bạn cần thêm quyền trong tệp kê khai.
Pria

4
ERIC.CALL_PRIVILEGED Giấy phép chỉ được cấp cho các ứng dụng hệ thống không có sẵn ở cấp ứng dụng.
CoDe

và đó là gì? nó sẽ không quay trở lại hoạt động của bạn
user924

24

Chúng tôi có cùng một vấn đề và quản lý để giải quyết nó bằng cách sử dụng a PhoneStateListenerđể xác định khi cuộc gọi kết thúc, nhưng ngoài ra chúng tôi phải thực finish()hiện hoạt động ban đầu trước khi bắt đầu lại startActivity, nếu không thì nhật ký cuộc gọi sẽ ở phía trước nó.


4
bạn có thể tránh điều này bằng cách sử dụng một phương pháp khác. nếu bạn xây dựng một ContentObserver quan sát nhật ký cuộc gọi Android, thì ứng dụng sẽ không bắt đầu cho đến khi thay đổi nhật ký cuộc gọi được thực hiện. tôi thực sự đã phải bỏ PhoneStateListener để ủng hộ mô hình này, vì ứng dụng của tôi cần dữ liệu nhật ký cuộc gọi và người nghe đã quay trở lại trước khi những thay đổi đó được thực hiện. pastebin.com/bq2s9EVa
moonlightcheese

11
@ André: liên kết của bạn dường như bị hỏng
tổng

Tôi sẽ cho bạn một triệu danh tiếng (nếu tôi có rất nhiều :)) Cảm ơn vì đã làm cho ngày của tôi!
keybee

1
Vấn đề với các liên kết tôi nói!
Dheeraj Bhaskar


13

Tôi đã tìm thấy EndCallListener là ví dụ chức năng nhất, để có được hành vi được mô tả (finish (), gọi, khởi động lại) Tôi đã thêm một vài SharedPreferences để Listener có một tham chiếu để quản lý hành vi này.

OnClick, khởi tạo và EndCallListener của tôi chỉ trả lời các cuộc gọi từ ứng dụng. Các cuộc gọi khác bị bỏ qua.

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

        }

    }
}

thêm những thứ này vào chuỗi

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

và một cái gì đó như thế này trong Bản kê khai của bạn nếu bạn cần quay lại giao diện trước khi gọi

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

và đặt những thứ này vào 'myActivity' của bạn

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

sử dụng điều này để khởi tạo hành vi cho onClick của bạn trong myActivity, ví dụ như sau 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();

}

Bạn sẽ thấy rằng việc nhấp vào danh sách các số điện thoại của bạn sẽ kết thúc hoạt động của bạn, thực hiện cuộc gọi đến số đó và trở về hoạt động của bạn khi cuộc gọi kết thúc.

Thực hiện cuộc gọi từ bên ngoài ứng dụng của bạn trong khi ứng dụng vẫn không khởi động lại hoạt động của bạn (trừ khi nó giống như số BParty cuối cùng được gọi).

:)


5
Xin lỗi nhưng mã này trông hơi xấu xí. Cảm ơn câu trả lời mặc dù
Pierre

7

bạn có thể sử dụng startActivityForResult ()


1
Sử dụng Android 5.0, phương thức onActivityResult được gọi ngay lập tức cuộc gọi bắt đầu !!
Panciz

6

Đây là giải pháp theo quan điểm của tôi:

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

    }

Tất nhiên trong định nghĩa Activity (lớp), bạn phải triển khai View.OnClickListener.


6

Dưới đây là ví dụ của tôi, đầu tiên người dùng sẽ ghi vào số mà anh ấy / cô ấy muốn quay số và sau đó nhấn nút gọi và được chuyển hướng đến điện thoại. Sau khi hủy cuộc gọi, người dùng sẽ được gửi trở lại ứng dụng. Để làm được điều này, nút cần phải có phương thức onClick ('makePhoneCall' trong ví dụ này) trong xml. Bạn cũng cần phải đăng ký sự cho phép trong bảng kê khai.

Rõ ràng

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

Hoạt động

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

bạn thậm chí không nói những gì bạn đang nói. READ_PHONE_STATE - bạn không sử dụng nó trong mã ví dụ của mình, tại sao bạn lại thêm nó? tất nhiên nó sẽ đưa bạn trở lại hoạt động ứng dụng của bạn nếu bạn nhấn nút hủy, nhưng tác giả của câu hỏi đã hỏi về cách quay lại hoạt động sau khi cuộc gọi được chấp nhận
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

Nếu bạn sẽ sử dụng một trình lắng nghe, bạn cũng sẽ cần phải thêm quyền này vào bảng kê khai.

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

3

Bên trong PhoneStateListener sau khi thấy cuộc gọi kết thúc, sử dụng tốt hơn:

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

Trong đó CallDispatcherActivity là hoạt động mà người dùng đã thực hiện cuộc gọi (đối với người điều phối dịch vụ taxi, trong trường hợp của tôi). Điều này chỉ cần loại bỏ ứng dụng điện thoại Android từ đầu, người dùng sẽ quay lại thay vì mã xấu mà tôi thấy ở đây.


1
Và đừng quên loại bỏ người nghe sau khi kết thúc cuộc gọi điện thoại, như thế này:((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE);
Dmitri Novikov

Tôi đã thử sử dụng phương pháp của bạn nhưng hoạt động (được gọi là ControlPanel) không được kích hoạt lại. Màn hình tiếp tục hiển thị giao diện trình quay số điện thoại và bộ ghi nhật ký trên các điểm nhập onResume và onNewIntent trong ControlPanel hoàn toàn im lặng. Đây là ý định : Intent intentRestart = new Intent(ControlPanel.this, ControlPanel.class);. Tôi nên chỉ ra rằng PhoneStateListener cũng nằm trong ControlPanel. Tức là, mục tiêu của tôi là khôi phục giao diện người dùng về trạng thái trước khi bắt đầu cuộc gọi điện thoại. Bất kỳ đề xuất?
PeteH

Hãy thử đăng nhập bên trong triển khai PhoneStateListener của bạn.
Dmitri Novikov

3

Để trở về với bạn Activity, bạn sẽ cần lắng nghe TelephonyStates. Trên đó listenerbạn có thể gửi một Intentđể mở lạiActivity một khi điện thoại không hoạt động.

Ít nhất đó là cách tôi sẽ làm điều đó.


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

Hãy thử sử dụng:

finish();

vào cuối hoạt động. Nó sẽ chuyển hướng bạn đến hoạt động trước đó của bạn.


2

Khi nào PhoneStateListener được sử dụng, người ta cần đảm bảo PHONE_STATE_IDLEtheo a PHONE_STATE_OFFHOOKđược sử dụng để kích hoạt hành động được thực hiện sau cuộc gọi. Nếu kích hoạt xảy ra khi nhìn thấy PHONE_STATE_IDLE, bạn sẽ kết thúc việc đó trước cuộc gọi. Bởi vì bạn sẽ thấy sự thay đổi trạng tháiPHONE_STATE_IDLE -> PHONE_STATE_OFFHOOK -> PHONE_STATE_IDLE.


không thể ứng dụng dừng lại khi màn hình cuộc gọi đang diễn ra?
lisovaccaro

Đối tượng người nghe một khi được đặt để nghe TelephonyManager với ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(new PhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE)sẽ tiếp tục nghe trạng thái điện thoại và hoạt động cho đến khi dừng rõ ràng với((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE)
PonMaran

2

// trong setonclicklistener đặt mã này:

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

// cấp phép cho cuộc gọi trong tệp kê khai:

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

1

@Dmitri Novikov, FLAG_ACTIVITY_CLEAR_TOPxóa bất kỳ trường hợp hoạt động nào trên đầu trang mới. Vì vậy, nó có thể kết thúc trường hợp cũ trước khi hoàn thành quá trình.



1

Các bước:

1) Thêm các quyền cần thiết trong Manifest.xmltập tin.

<!--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) Tạo người nghe cho các thay đổi trạng thái điện thoại.

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) Khởi tạo người nghe trong của bạn OnCreate

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

nhưng nếu bạn muốn tiếp tục ứng dụng của mình ở trạng thái cuối hoặc để đưa nó trở lại từ ngăn xếp phía sau , thì hãy thay thếFLAG_ACTIVITY_CLEAR_TOP bằngFLAG_ACTIVITY_SINGLE_TOP

Tham khảo câu trả lời này



0

Khi bắt đầu cuộc gọi của bạn, nó có vẻ tốt.

Có một sự khác biệt giữa Android 11+ trở xuống trong việc đưa ứng dụng của bạn lên phía trước.

Android 10 trở xuống bạn cần bắt đầu một ý định mới, Android 11+ bạn chỉ cần sử dụng BringTaskToFront

Trong trạng thái cuộc gọi 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);
}

Tôi đặt lệnh MyActivity.MyActivityTaskIdkhi thực hiện cuộc gọi trên hoạt động của mình như vậy, nó không hoạt động, đặt biến này trên trang hoạt động chính của trang bạn muốn quay lại.

MyActivity.MyActivityTaskId = this.getTaskId();

MyActivityTaskId là một biến tĩnh trên lớp hoạt động của tôi

public static int MyActivityTaskId = 0;

Tôi hy vọng điều này sẽ làm việc cho bạn. Tôi sử dụng mã ở trên một chút khác nhau, tôi mở ứng dụng của mình ngay khi cuộc gọi được trả lời, người dùng có thể thấy chi tiết của người gọi.

Tôi cũng đã thiết lập một số thứ AndroidManifest.xml:

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

và quyền:

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

Vui lòng đặt câu hỏi nếu hoặc khi bạn gặp khó khăn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.