Android 기기에서 수신 전화를 감지하는 방법은 무엇입니까?


130

전화가 올 때 전화를 걸 때 전화 번호를 감지하고 싶은 것처럼 앱을 만들려고합니다. 아래는 내가 시도한 것이지만 수신 전화를 감지하지 못합니다.

MainActivity백그라운드에서 달리기를 원합니다. 어떻게해야합니까?

manifest파일에 권한을 부여했습니다 .

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

매니페스트에 추가해야 할 것이 있습니까?

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

우리는 안드로이드 P 무엇을해야합니까
아마드 아르 슬란

답변:


336

이 작업을 수행하는 데 사용하는 내용은 다음과 같습니다.

명백한:

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

내 기본 재사용 가능한 통화 감지기

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

그런 다음 클래스를 사용하여 클래스를 파생시키고 몇 가지 쉬운 함수를 구현하십시오.

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)
    {
        //
    }

}

또한 코드가 내 블로그 에있는 것과 같은 이유에 대한 글을 볼 수 있습니다 . 요점 링크 : https://gist.github.com/ftvs/e61ccb039f511eb288ee

편집 : 내가 사용하기 위해 클래스를 재 작업 했으므로 더 간단한 코드로 업데이트되었습니다.


2
이 코드는 아무것도 표시하지 않습니다. 발신 전화가 시작 / 종료 될 때 전화를 걸고 번호, 시작 시간 및 완료 시간을 전달합니다. 실제로 그것을 표시하는 방법을 알 수있는 방법이 없기 때문에 실제로 표시하는 것은 당신의 일입니다.
Gabe Sechan

3
@GabeSechan : 대단해! 통화 대기 상황을 처리하도록 안내해 주시겠습니까?
Mehul Joisar

6
그냥 응용 프로그램 전경 또는 배경하지 않을 때 나는 수신기이 추가 될 때까지 작동하지 않았다,이에 추가 : "안드로이드 : 활성화 =" "사실
라자 샤르마

1
정적 변수는 응용 프로그램이 메모리에서 쫓겨날 때까지 유지됩니다 (서비스가 실행 중인지 및 일반적인 전화 메모리 조건에 따라 상당히 오래 걸릴 수 있음). 그러나 네, 그들은 길을 잃을 수 있습니다. 공유 환경 설정을 통해 디스크에 쓸 수는 있지만 잘못된 결과를 초래할 수 있습니다. 전화 재부팅과 같은 여러 경우에 데이터를 올바르게 지울 수 없습니다. 내 유스 케이스의 경우 드문 null 및 손실 된 데이터가 잘못된 데이터보다 낫습니다. 필요에 따라 이것을 자유롭게 돌리십시오.
Gabe Sechan

1
@GabeSechan : 버그가있는 것 같습니다. lastState 로 초기화하면 안됩니다 CALL_STATE_IDLE. 현재 상태가 인 상태에서 앱이 종료되면 호출이 거의 없습니다 RINGING. 그것은지면 때문에 IDLE통화가 끝나면 다시 정적 변수로 재 초기화되고 CALL_STATE_IDLE그리고 아무것도하지 않는 디 바운스. 따라서에 대한 참조를 잃습니다 lastState.
Heisenberg

23
private MyPhoneStateListener phoneStateListener = new MyPhoneStateListener();

등록하기

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

등록 취소

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

mainactivity에서 이것을 어디에서 사용해야합니까?
Jesbin MJ

어디 변경 사항을 듣고 수업이 배치 .. 일반적으로 레지스터들의 OnDestroy에서 한 OnCreate 및 등록 취소에 완료 .. 수업 시간에 전 세계적으로 객체를 선언
stinepike

이 옵션에는 권한이 필요하지 않습니다.
Mike

Gabe의 솔루션은 Viber 종류의 앱과 같은보다 관입적인 기능에 더 적합하지만 전화 통화의 사용자 행동에 단순히 반응해야하는 사람들에게 가장 적합한 솔루션입니다. 이와 같은 경우 런타임 권한을 요청하는 것은 과잉 일 가능성이 높으며 사용자가 제대로 수신하지 못할 수 있습니다.
bosphere

1
전화가 올 때이 코드로 어떻게 할 수 있습니까?
누르 호사 인

14

Android P-Api Level 28 : READ_CALL_LOG 권한이 필요합니다

통화 기록에 대한 제한된 액세스

안드로이드 P는 이동 CALL_LOG, READ_CALL_LOG, WRITE_CALL_LOG, 및 PROCESS_OUTGOING_CALLS로부터 권한을 PHONE새로운 권한 그룹을 CALL_LOG권한 그룹. 이 그룹은 사용자에게 전화 통화 기록 읽기 및 전화 번호 식별과 같은 전화 통화에 대한 민감한 정보에 액세스해야하는 앱에 대한 제어 및 가시성을 향상시킵니다.

PHONE_STATE 의도 행동에서 숫자를 읽으려면, 당신은 둘 다 필요한 READ_CALL_LOG허가와 READ_PHONE_STATE권한을 . 에서 숫자를 읽으려면 onCallStateChanged()이제 READ_CALL_LOG권한 만 있으면됩니다. 더 이상 READ_PHONE_STATE권한이 필요하지 않습니다 .


단지 추가하는 사람들 READ_CALL_LOGAndroidManifest.xml의 권한 요청을 추가하는 방법에 초점 MainActivity.
Piyush

13

업데이트 : Gabe Sechan이 게시 한 멋진 코드는 사용자에게 필요한 권한을 부여하도록 명시 적으로 요청하지 않으면 더 이상 작동하지 않습니다. 다음은 이러한 권한을 요청하기 위해 기본 활동에 배치 할 수있는 코드입니다.

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

또한 : Gabe의 게시물 아래의 주석에서 언급 한 것처럼 android:enabled="true앱이 현재 포 그라운드에서 실행되고 있지 않을 때 수신 전화를 감지하려면 수신기에 코드 스 니펫을 추가해야합니다 .

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

응용 프로그램에 활동이없고 브로드 캐스트 수신자와 서비스 만있는 경우 어떻게해야합니까? 그런 다음 브로드 캐스트 수신자가이 권한이 부여 될 때까지 호출되지 않으므로 사용자로부터 권한을 얻기 위해이 코드를 어디에 작성해야합니까?
user2779311

2
MainActivity가 한 번만 열리더라도 최소한 MainActivity가 필요합니다. 통화 차단 앱 RoboStop 예를 들어 : 사용자가 앱을 처음 다운로드 한 다음 앱 아이콘을 클릭하여 앱을 시작하면 앱에 필요한 권한을 부여하라는 메시지가 표시됩니다. 이 앱에는 통화 차단을 활성화 / 비활성화하는 버튼이 있지만 사용자는 앱 / 활동을 다시 시작할 필요가 없으며 사용자가 앱 / 활동을 다시 시작하지 않고도 백그라운드에서 통화 차단이 이루어집니다.
topherPedersen

이것을 구현하는 데 어려움이있는 분들은이 튜토리얼 studytutorial.in/…을
Prasath

5

이것은 당신을 도울 수 있고 또한 permsion을 요구합니다

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
이것은 괜찮은 것 같습니다. 그러나 활동에서 어떻게 사용할 수 있습니까? 자세한 내용을 알려주십시오
Amir

4

Gabe Sechan의 답변을 업데이트하십시오. 매니페스트에서 READ_CALL_LOG 및 READ_PHONE_STATE에 대한 권한을 요청하면 onReceive는 TWICE 라고 합니다. 그중 하나는 EXTRA_INCOMING_NUMBER를 가지고 있고 다른 하나는 그렇지 않습니다. 어떤 것이 있는지 테스트해야하며 어떤 순서로든 발생할 수 있습니다.

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


2

다음은 사용 PhonestateListener및 기타 합병증을 피할 수있는 간단한 방법입니다 .
그래서 여기에 우리는 안드로이드와 같은에서와 같은 3 개 이벤트를 받고 RINGING, OFFHOOK하고 IDLE. 그리고 호출의 모든 가능한 상태를 얻기 위해, 우리는 우리 자신의 상태가 좋아 정의 할 필요가 RINGING, OFFHOOK, IDLE, FIRST_CALL_RINGING, SECOND_CALL_RINGING. 전화 통화의 모든 상태를 처리 할 수 ​​있습니다.
우리가 안드로이드에서 이벤트를 수신하는 방식으로 생각하고 우리는 호출 상태를 정의 할 것입니다. 코드를 참조하십시오.

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, 코드 주셔서 감사합니다. 를 제외하고는 잘 작동합니다 onOutgoingCallEnded(). 절대 실행되지 않습니다. 테스트 전화는 Samsung S5 & Trendy입니다. 내가 생각하는 두 가지 버그가 있습니다.

1 : 괄호 쌍이 없습니다.

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 : 함수의 끝에 lastState있는 state경우에 의해 업데이트되지 않습니다 . 이 함수의 첫 번째 줄로 바꿔야합니다.

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;
    }
    //....
}

추가 내가 넣었습니다 lastState그리고 savedNumber당신이 제안 공유 취향에.

위의 변경 사항으로 테스트했습니다. 휴대폰에서 버그가 수정되었습니다.


0

아래 코드를 사용하십시오. 다른 전화 세부 정보로 수신 번호를 얻는 데 도움이됩니다.

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

} 

매니페스트에서 다음과 같은 권한을 요청합니다.

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

READ_LOGS 이렇게하면 Play 스토어에서 앱 사용이 금지됩니다
Duna

0

브로드 캐스트 리시버가 필요합니다 ACTION_PHONE_STATE_CHANGED. 전화 상태가 유휴, 벨 울림, 오프 훅에서 이전 값 및 수신 / 발신 호출인지 감지 할 수있는 새 값에서 변경 될 때마다 수신을 호출합니다.

필요한 권한은 다음과 같습니다.

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

그러나 해당 방송에서 EXTRA_INCOMING_NUMBER을 (를) 수신하려면 "android.permission.READ_CALL_LOG"라는 다른 권한이 필요합니다.

그리고 코드는 다음과 같습니다.

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

그리고 수신기 클래스에서 다음과 같은 의도를 읽으면 현재 상태를 얻을 수 있습니다.

intent.extras["state"]

엑스트라의 결과는 다음과 같습니다.

벨소리-> 전화벨이 울리는 경우

OFFHOOK-> 다른 사람과 통화중인 경우 (수신 또는 발신 통화)

유휴-> 통화가 종료 된 경우 (수신 또는 발신 통화)

PHONE_STATE 브로드 캐스트를 사용하면 PROCESS_OUTGOING_CALLS 권한을 사용하거나 더 이상 사용되지 않는 NEW_OUTGOING_CALL 작업을 사용할 필요가 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.