Làm cách nào để phát hiện các cuộc gọi đến, trong thiết bị Android?


130

Tôi đang cố gắng tạo một ứng dụng như thế nào, khi có cuộc gọi đến điện thoại tôi muốn phát hiện số này. Dưới đây là những gì tôi đã thử, nhưng nó không phát hiện các cuộc gọi đến.

Tôi muốn chạy MainActivitynền của tôi , làm thế nào tôi có thể làm điều đó?

Tôi đã cho phép trong manifesttập tin.

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

Có bất cứ điều gì khác tôi nên cung cấp trong bảng kê khai?

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_layout);
   }

   public class myPhoneStateChangeListener extends PhoneStateListener {
       @Override
       public void onCallStateChanged(int state, String incomingNumber) {
           super.onCallStateChanged(state, incomingNumber);
           if (state == TelephonyManager.CALL_STATE_RINGING) {
               String phoneNumber =   incomingNumber;
           }
       }
   }
}

Chúng ta nên làm gì cho Android P
Ahmad Arslan

Câu trả lời:


336

Đây là những gì tôi sử dụng để làm điều này:

Rõ ràng:

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

<!--This part is inside the application-->
    <receiver android:name=".CallReceiver" >
        <intent-filter>
            <action android:name="android.intent.action.PHONE_STATE" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
        </intent-filter>
    </receiver>

Cơ sở của tôi phát hiện cuộc gọi tái sử dụng

package com.gabesechan.android.reusable.receivers;

import java.util.Date;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;

public abstract class PhonecallReceiver extends BroadcastReceiver {

    //The receiver will be recreated whenever android feels like it.  We need a static variable to remember data between instantiations

    private static int lastState = TelephonyManager.CALL_STATE_IDLE;
    private static Date callStartTime;
    private static boolean isIncoming;
    private static String savedNumber;  //because the passed incoming is only valid in ringing


    @Override
    public void onReceive(Context context, Intent intent) {

        //We listen to two intents.  The new outgoing call only tells us of an outgoing call.  We use it to get the number.
        if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) {
            savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER");
        }
        else{
            String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
            String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
            int state = 0;
            if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)){
                state = TelephonyManager.CALL_STATE_IDLE;
            }
            else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
                state = TelephonyManager.CALL_STATE_OFFHOOK;
            }
            else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)){
                state = TelephonyManager.CALL_STATE_RINGING;
            }


            onCallStateChanged(context, state, number);
        }
    }

    //Derived classes should override these to respond to specific events of interest
    protected abstract void onIncomingCallReceived(Context ctx, String number, Date start);
    protected abstract void onIncomingCallAnswered(Context ctx, String number, Date start);
    protected abstract void onIncomingCallEnded(Context ctx, String number, Date start, Date end);

    protected abstract void onOutgoingCallStarted(Context ctx, String number, Date start);      
    protected abstract void onOutgoingCallEnded(Context ctx, String number, Date start, Date end);

    protected abstract void onMissedCall(Context ctx, String number, Date start);

    //Deals with actual events

    //Incoming call-  goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up
    //Outgoing call-  goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up
    public void onCallStateChanged(Context context, int state, String number) {
        if(lastState == state){
            //No change, debounce extras
            return;
        }
        switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:
                isIncoming = true;
                callStartTime = new Date();
                savedNumber = number;
                onIncomingCallReceived(context, number, callStartTime);
                break;
            case TelephonyManager.CALL_STATE_OFFHOOK:
                //Transition of ringing->offhook are pickups of incoming calls.  Nothing done on them
                if(lastState != TelephonyManager.CALL_STATE_RINGING){
                    isIncoming = false;
                    callStartTime = new Date();
                    onOutgoingCallStarted(context, savedNumber, callStartTime);                     
                }
                else
                {
                    isIncoming = true;
                    callStartTime = new Date();
                    onIncomingCallAnswered(context, savedNumber, callStartTime); 
                }

                break;
            case TelephonyManager.CALL_STATE_IDLE:
                //Went to idle-  this is the end of a call.  What type depends on previous state(s)
                if(lastState == TelephonyManager.CALL_STATE_RINGING){
                    //Ring but no pickup-  a miss
                    onMissedCall(context, savedNumber, callStartTime);
                }
                else if(isIncoming){
                    onIncomingCallEnded(context, savedNumber, callStartTime, new Date());                       
                }
                else{
                    onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());                                               
                }
                break;
        }
        lastState = state;
    }
}

Sau đó, để sử dụng nó, chỉ cần lấy một lớp từ nó và thực hiện một vài hàm dễ dàng, bất kỳ kiểu gọi nào bạn quan tâm:

public class CallReceiver extends PhonecallReceiver {

    @Override
    protected void onIncomingCallReceived(Context ctx, String number, Date start)
    {
        //
    }

    @Override
    protected void onIncomingCallAnswered(Context ctx, String number, Date start)
    {
        //
    }

    @Override
    protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end)
    {
        //
    }

    @Override
    protected void onOutgoingCallStarted(Context ctx, String number, Date start)
    {
        //
    } 

    @Override 
    protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end)
    {
        //
    }

    @Override
    protected void onMissedCall(Context ctx, String number, Date start)
    {
        //
    }

}

Ngoài ra, bạn có thể thấy một bài viết tôi đã làm về lý do tại sao mã giống như trên blog của tôi . Liên kết chính: https://gist.github.com/ftvs/e61ccb039f511eb288ee

EDIT: Được cập nhật thành mã đơn giản hơn, vì tôi đã làm lại lớp để sử dụng cho riêng mình


2
Mã này không hiển thị bất cứ điều gì. Những gì nó làm là gọi cho bạn khi một cuộc gọi đi bắt đầu / kết thúc và chuyển cho bạn số, thời gian bắt đầu và thời gian kết thúc. Thực tế hiển thị nó là công việc của bạn, bởi vì tôi không có cách nào để biết bạn muốn nó được thực hiện như thế nào.
Gabe Sechan

3
@GabeSechan: Tuyệt vời! bạn có thể vui lòng hướng dẫn tôi xử lý tình huống chờ cuộc gọi không?
Mehul Joisar

6
Chỉ cần thêm vào điều này, nó không hoạt động khi ứng dụng không ở nền trước hoặc nền cho đến khi tôi thêm phần này vào trình nhận: "android: enable =" true "
Rajat Sharma

1
Các biến tĩnh sẽ tồn tại xung quanh cho đến khi ứng dụng bị loại khỏi bộ nhớ (có thể khá lâu, tùy thuộc vào việc các dịch vụ có chạy hay không và điều kiện bộ nhớ điện thoại nói chung). Nhưng vâng, họ có thể bị mất. Bạn có thể ghi nó vào đĩa, thông qua tùy chọn chia sẻ nhưng điều đó có thể khiến bạn có kết quả sai - điều đó sẽ ngăn bạn xóa dữ liệu của mình đúng cách trong một số trường hợp, chẳng hạn như khởi động lại điện thoại. Đối với trường hợp sử dụng của tôi, dữ liệu null và dữ liệu bị mất hiếm hơn là dữ liệu không chính xác. Hãy thoải mái xoay vòng với điều này theo nhu cầu của bạn.
Gabe Sechan

1
@GabeSechan: Dường như có một lỗi trong đó. lastState không nên được khởi tạo để CALL_STATE_IDLE. Tôi bị thiếu một vài cuộc gọi khi ứng dụng của tôi bị giết trong khi trạng thái hiện tại là RINGING. Bởi vì khi nó trở IDLElại khi kết thúc cuộc gọi, biến tĩnh được khởi tạo lại CALL_STATE_IDLEvà nó sẽ không làm gì cả. Vì vậy, chúng tôi mất tham chiếu đến lastState.
Heisenberg

23
private MyPhoneStateListener phoneStateListener = new MyPhoneStateListener();

đăng ký

TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);

và hủy đăng ký

TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);

Tôi nên sử dụng cái này ở đâu?
Jesbin MJ

đặt cái này trong lớp nơi bạn đang lắng nghe sự thay đổi .. thông thường các thanh ghi được thực hiện trong oncreate và unregister in ondestroy .. khai báo đối tượng trên toàn cầu trong lớp
stinepike

Tùy chọn này không yêu cầu quyền.
Mike

trong khi giải pháp của Gabe phù hợp hơn với các tính năng xâm nhập hơn, ví dụ như loại ứng dụng Viber, đây là giải pháp tốt nhất cho những người cần phản ứng đơn giản với hành động của người dùng khi gọi điện thoại. Yêu cầu quyền thời gian chạy trong các trường hợp như thế này rất có thể là quá mức cần thiết và có thể không được người dùng đón nhận.
bosphere

1
Tôi muốn làm một cái gì đó, khi cuộc gọi đến, làm thế nào với mã này?
Noor Hossain

14

Với Android P - Api Cấp 28: Bạn cần có quyền READ_CALL_LOG

Truy cập hạn chế vào nhật ký cuộc gọi

Android P di chuyển CALL_LOG, READ_CALL_LOG, WRITE_CALL_LOG, và PROCESS_OUTGOING_CALLSquyền từ PHONEnhóm phép mới CALL_LOGnhóm được phép. Nhóm này cung cấp cho người dùng quyền kiểm soát và khả năng hiển thị tốt hơn đối với các ứng dụng cần truy cập vào thông tin nhạy cảm về các cuộc gọi điện thoại, chẳng hạn như đọc hồ sơ cuộc gọi điện thoại và xác định số điện thoại.

Để đọc số từ hành động mục đích PHONE_STATE, bạn cần cả READ_CALL_LOGquyền và READ_PHONE_STATEquyền . Để đọc số từ onCallStateChanged(), bây giờ bạn chỉ cần sự READ_CALL_LOGcho phép. Bạn không còn cần sự READ_PHONE_STATEcho phép.


đối với những người chỉ được thêm READ_CALL_LOGvào AndroidManifest.xmltập trung vào việc thêm một yêu cầu sự cho phép trong MainActivity.
Piyush

13

CẬP NHẬT: Mã thực sự tuyệt vời được đăng bởi Gabe Sechan không còn hoạt động trừ khi bạn yêu cầu rõ ràng người dùng cấp các quyền cần thiết. Đây là một số mã mà bạn có thể đặt trong hoạt động chính của mình để yêu cầu các quyền này:

    if (getApplicationContext().checkSelfPermission(Manifest.permission.READ_PHONE_STATE)
            != PackageManager.PERMISSION_GRANTED) {
        // Permission has not been granted, therefore prompt the user to grant permission
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.READ_PHONE_STATE},
                MY_PERMISSIONS_REQUEST_READ_PHONE_STATE);
    }

    if (getApplicationContext().checkSelfPermission(Manifest.permission.PROCESS_OUTGOING_CALLS)
            != PackageManager.PERMISSION_GRANTED) {
        // Permission has not been granted, therefore prompt the user to grant permission
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.PROCESS_OUTGOING_CALLS},
                MY_PERMISSIONS_REQUEST_PROCESS_OUTGOING_CALLS);
    }

CSONG: Như ai đó đã đề cập trong một bình luận bên dưới bài đăng của Gabe , bạn phải thêm một đoạn mã nhỏ android:enabled="true, vào máy thu để phát hiện các cuộc gọi đến khi ứng dụng hiện không chạy ở nền trước:

    <!--This part is inside the application-->
    <receiver android:name=".CallReceiver" android:enabled="true">
        <intent-filter>
            <action android:name="android.intent.action.PHONE_STATE" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
        </intent-filter>
    </receiver>

Điều gì xảy ra nếu ứng dụng không có bất kỳ Hoạt động nào và chỉ có người phát sóng và dịch vụ. Sau đó, chúng tôi viết mã này ở đâu để có được sự cho phép từ người dùng vì người phát sóng sẽ không được gọi cho đến khi quyền này được đưa ra.
dùng2779311

2
Bạn ít nhất cần một MainActivity ngay cả khi nó chỉ được mở một lần. Lấy ứng dụng chặn cuộc gọi của tôi RoboStop chẳng hạn: Khi người dùng tải xuống ứng dụng lần đầu tiên, sau đó nhấp vào biểu tượng ứng dụng để khởi chạy ứng dụng, sau đó họ sẽ được nhắc cấp cho ứng dụng của tôi các quyền cần thiết. Ứng dụng cũng có một nút để bật / tắt chặn cuộc gọi, nhưng người dùng không cần phải khởi chạy lại ứng dụng / hoạt động, việc chặn cuộc gọi sẽ diễn ra trong nền mà không cần người dùng phải khởi chạy lại ứng dụng / hoạt động.
topherPedersen

Những người gặp khó khăn trong việc thực hiện điều này, hãy làm theo hướng dẫn này nghiên cứu hướng dẫn.in / từ
Prasath

5

điều này có thể giúp bạn và cũng thêm yêu cầu hoán vị

public class PhoneListener extends PhoneStateListener
{
    private Context context;
    public static String getincomno;

    public PhoneListener(Context c) {
        Log.i("CallRecorder", "PhoneListener constructor");
        context = c;
    }

    public void onCallStateChanged (int state, String incomingNumber)
    {

        if(!TextUtils.isEmpty(incomingNumber)){
        // here for Outgoing number make null to get incoming number
        CallBroadcastReceiver.numberToCall = null;
        getincomno = incomingNumber;
        }

        switch (state) {
        case TelephonyManager.CALL_STATE_IDLE:

            break;
        case TelephonyManager.CALL_STATE_RINGING:
            Log.d("CallRecorder", "CALL_STATE_RINGING");
            break;
        case TelephonyManager.CALL_STATE_OFFHOOK:

            break;
        }
    }
}

2
điều này có vẻ tốt Nhưng làm thế nào tôi có thể sử dụng nó từ hoạt động? xin vui lòng cho tôi biết chi tiết
Amir

4

Chỉ cần cập nhật câu trả lời của Gabe Sechan. Nếu tệp kê khai của bạn yêu cầu quyền đối với READ_CALL_LOG và READ_PHONE_STATE, onReceive sẽ được gọi là TWICE . Một trong số đó có EXTRA_INCOMING_NUMBER trong đó và cái kia thì không. Bạn phải kiểm tra cái nào có nó và nó có thể xảy ra theo bất kỳ thứ tự nào.

https://developer.android.com/reference/android/telephony/TelephonyManager.html#ACTION_PHONE_STATE_CHANGED


2

Đây là một phương pháp đơn giản có thể tránh sử dụng PhonestateListenervà các biến chứng khác.
Vì vậy, ở đây chúng tôi đang nhận được 3 sự kiện từ Android như RINGING, OFFHOOKIDLE. Và để có được tất cả các trạng thái có thể có của cuộc gọi, chúng ta cần phải xác định trạng thái của chúng ta thích RINGING, OFFHOOK, IDLE, FIRST_CALL_RINGING, SECOND_CALL_RINGING. Nó có thể xử lý mọi trạng thái trong một cuộc gọi điện thoại.
Vui lòng nghĩ theo cách mà chúng tôi đang nhận sự kiện từ Android và chúng tôi sẽ xác định trạng thái cuộc gọi của chúng tôi. Xem mã.

public class CallListening  extends BroadcastReceiver {
    private static final String TAG ="broadcast_intent";
    public static String incoming_number;
    private String current_state,previus_state,event;
    public static Boolean dialog= false;
    private Context context;
    private SharedPreferences sp,sp1;
    private SharedPreferences.Editor spEditor,spEditor1;
    public void onReceive(Context context, Intent intent) {
        //Log.d("intent_log", "Intent" + intent);
        dialog=true;
        this.context = context;
        event = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
        incoming_number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
        Log.d(TAG, "The received event : "+event+", incoming_number : " + incoming_number);
        previus_state = getCallState(context);
        current_state = "IDLE";
        if(incoming_number!=null){
            updateIncomingNumber(incoming_number,context);
        }else {
            incoming_number=getIncomingNumber(context);
        }
        switch (event) {
            case "RINGING":
                Log.d(TAG, "State : Ringing, incoming_number : " + incoming_number);
            if((previus_state.equals("IDLE")) || (previus_state.equals("FIRST_CALL_RINGING"))){
                    current_state ="FIRST_CALL_RINGING";
                }
                if((previus_state.equals("OFFHOOK"))||(previus_state.equals("SECOND_CALL_RINGING"))){
                    current_state = "SECOND_CALL_RINGING";
                }

                break;
            case "OFFHOOK":
                Log.d(TAG, "State : offhook, incoming_number : " + incoming_number);
                if((previus_state.equals("IDLE")) ||(previus_state.equals("FIRST_CALL_RINGING")) || previus_state.equals("OFFHOOK")){
                    current_state = "OFFHOOK";
                }
                if(previus_state.equals("SECOND_CALL_RINGING")){
                    current_state ="OFFHOOK";
                    startDialog(context);
                }
                break;
            case "IDLE":
                Log.d(TAG, "State : idle and  incoming_number : " + incoming_number);
                if((previus_state.equals("OFFHOOK")) || (previus_state.equals("SECOND_CALL_RINGING")) || (previus_state.equals("IDLE"))){
                    current_state="IDLE";
                }
                if(previus_state.equals("FIRST_CALL_RINGING")){
                    current_state = "IDLE";
                    startDialog(context);
                }
                updateIncomingNumber("no_number",context);
                Log.d(TAG,"stored incoming number flushed");
                break;
        }
        if(!current_state.equals(previus_state)){
            Log.d(TAG, "Updating  state from "+previus_state +" to "+current_state);
            updateCallState(current_state,context);

        }
    }
    public void startDialog(Context context) {
        Log.d(TAG,"Starting Dialog box");
        Intent intent1 = new Intent(context, NotifyHangup.class);
        intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent1);

    }
    public void updateCallState(String state,Context context){
        sp = PreferenceManager.getDefaultSharedPreferences(context);
        spEditor = sp.edit();
        spEditor.putString("call_state", state);
        spEditor.commit();
        Log.d(TAG, "state updated");

    }
    public void updateIncomingNumber(String inc_num,Context context){
        sp = PreferenceManager.getDefaultSharedPreferences(context);
        spEditor = sp.edit();
        spEditor.putString("inc_num", inc_num);
        spEditor.commit();
        Log.d(TAG, "incoming number updated");
    }
    public String getCallState(Context context){
        sp1 = PreferenceManager.getDefaultSharedPreferences(context);
        String st =sp1.getString("call_state", "IDLE");
        Log.d(TAG,"get previous state as :"+st);
        return st;
    }
    public String getIncomingNumber(Context context){
        sp1 = PreferenceManager.getDefaultSharedPreferences(context);
        String st =sp1.getString("inc_num", "no_num");
        Log.d(TAG,"get incoming number as :"+st);
        return st;
    }
}

0

@Gabe Sechan, cảm ơn mã của bạn. Nó hoạt động tốt, ngoại trừ onOutgoingCallEnded(). Nó không bao giờ được thực hiện. Điện thoại thử nghiệm là Samsung S5 & Hợp thời trang. Có 2 lỗi tôi nghĩ.

1: một cặp dấu ngoặc bị thiếu.

case TelephonyManager.CALL_STATE_IDLE: 
    // Went to idle-  this is the end of a call.  What type depends on previous state(s)
    if (lastState == TelephonyManager.CALL_STATE_RINGING) {
        // Ring but no pickup-  a miss
        onMissedCall(context, savedNumber, callStartTime);
    } else {
        // this one is missing
        if(isIncoming){
            onIncomingCallEnded(context, savedNumber, callStartTime, new Date());                       
        } else {
            onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());                                               
        }
    }
    // this one is missing
    break;

2: lastStatekhông được cập nhật bởi statenếu nó ở cuối hàm. Nó nên được thay thế cho dòng đầu tiên của chức năng này bằng

public void onCallStateChanged(Context context, int state, String number) {
    int lastStateTemp = lastState;
    lastState = state;
    // todo replace all the "lastState" by lastStateTemp from here.
    if (lastStateTemp  == state) {
        //No change, debounce extras
        return;
    }
    //....
}

Bổ sung Tôi đã đặt lastStatesavedNumbervào sở thích chung như bạn đề xuất.

Chỉ cần thử nghiệm nó với những thay đổi ở trên. Sửa lỗi ít nhất trên điện thoại của tôi.


0

Vui lòng sử dụng mã dưới đây. Nó sẽ giúp bạn có được số đến với các chi tiết cuộc gọi khác.

Activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >

<TextView
    android:id="@+id/call"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    android:text="@string/hello_world" />

</RelativeLayout>

MainActivity.java

public class MainActivity extends Activity {

private static final int MISSED_CALL_TYPE = 0;
private TextView txtcall;

@Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    txtcall = (TextView) findViewById(R.id.call);

    StringBuffer sb = new StringBuffer();
    Cursor managedCursor = managedQuery(CallLog.Calls.CONTENT_URI, null,
            null, null, null);
    int number = managedCursor.getColumnIndex(CallLog.Calls.NUMBER);
    int type = managedCursor.getColumnIndex(CallLog.Calls.TYPE);
    int date = managedCursor.getColumnIndex(CallLog.Calls.DATE);
    int duration = managedCursor.getColumnIndex(CallLog.Calls.DURATION);
    sb.append("Call Details :");
    while (managedCursor.moveToNext()) {
        String phNumber = managedCursor.getString(number);
        String callType = managedCursor.getString(type);
        String callDate = managedCursor.getString(date);
        Date callDayTime = new Date(Long.valueOf(callDate));
        String callDuration = managedCursor.getString(duration);
        String dir = null;
        int dircode = Integer.parseInt(callType);
        switch (dircode) {

        case CallLog.Calls.OUTGOING_TYPE:
            dir = "OUTGOING";
            break;

        case CallLog.Calls.INCOMING_TYPE:
            dir = "INCOMING";
            break;

        case CallLog.Calls.MISSED_TYPE:
            dir = "MISSED";
            break;
        }
        sb.append("\nPhone Number:--- " + phNumber + " \nCall Type:--- "
                + dir + " \nCall Date:--- " + callDayTime
                + " \nCall duration in sec :--- " + callDuration);
        sb.append("\n----------------------------------");
    }
    managedCursor.close();
    txtcall.setText(sb);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}

} 

và trong yêu cầu kê khai của bạn cho các quyền sau:

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

READ_LOGS làm như vậy để bạn bị cấm ứng dụng khỏi cửa hàng chơi
Duna

0

Bạn cần một BroadcastReceiver cho ACTION_PHONE_STATE_CHANGEDĐiều này sẽ gọi cho bạn nhận được bất cứ khi nào trạng thái điện thoại thay đổi từ nhàn rỗi, đổ chuông, chuyển đổi từ giá trị trước đó và giá trị mới bạn có thể phát hiện nếu đây là cuộc gọi đến / đi.

Sự cho phép cần thiết sẽ là:

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

Nhưng nếu bạn cũng muốn nhận EXTRA_INCOMING_NUMBER trong chương trình phát sóng đó, bạn sẽ cần một sự cho phép khác: "ERIC.READ_CALL_LOG"

Và mã giống như thế này:

val receiver: BroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d(TAG, "onReceive")
    }
}

override fun onResume() {
    val filter = IntentFilter()
    filter.addAction("android.intent.action.PHONE_STATE")
    registerReceiver(receiver, filter)
    super.onResume()
}

override fun onPause() {
    unregisterReceiver(receiver)
    super.onPause()
}

và trong lớp người nhận, chúng ta có thể có được trạng thái hiện tại bằng cách đọc ý định như thế này:

intent.extras["state"]

kết quả của các tính năng bổ sung có thể là:

RINGING -> Nếu điện thoại của bạn đổ chuông

OFFHOOK -> Nếu bạn đang nói chuyện với ai đó (Cuộc gọi đến hoặc Cuộc gọi đến)

IDLE -> nếu cuộc gọi kết thúc (Cuộc gọi đến hoặc cuộc gọi đến)

Với PHONE_STATE phát sóng, chúng tôi không cần phải sử dụng quyền PROCESS_OUTGOING_CALLS hoặc không được chấp nhận hành động NEW_OUTGOING_CALL.

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.