如何在 Android 设备中检测来电?

我正在尝试做一个应用程序,比如,当一个电话打到手机上时,我希望能够检测到这个号码。下面是我试过的,但是没有检测到来电。

我想在后台运行我的 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;
}
}
}
}
178515 次浏览
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);

我是这么做的:

舱单:

<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

编辑: 更新为更简单的代码,因为我已经为自己的使用重新编写了类

这可能会帮助您,也添加需要许可

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

@ Gabe Sechan 谢谢你的密码。除了 onOutgoingCallEnded()之外,其他都很好用。它从未被执行过。测试手机是三星 S5 & 时尚。我想有两只虫子。

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

另外,我已经按照你的建议将 lastStatesavedNumber放入共享首选项中。

刚刚测试了以上的变化。错误修复至少在我的手机。

这是一个简单的方法,可以避免使用 PhonestateListener和其他并发症。
这里我们收到了来自机器人的3个事件,比如 RINGINGOFFHOOKIDLE。为了得到所有可能的呼叫状态,我们需要定义我们自己的状态,如 RINGINGOFFHOOKIDLEFIRST_CALL_RINGINGSECOND_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;
}
}

更新: 除非您明确请求用户授予必要的权限,否则 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);
}

另外: 正如有人在下面的评论中提到的,你必须添加一个代码片段,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>

使用 Android P-Api Level 28: 您需要获得 READ _ CALL _ LOG 权限

通话记录访问受限

Android P 将 CALL_LOGREAD_CALL_LOGWRITE_CALL_LOGPROCESS_OUTGOING_CALLS权限从 PHONE权限组移动到新的 CALL_LOG权限组。这个小组让用户对需要访问电话通话敏感信息的应用程序有更好的控制和可见性,比如阅读电话通话记录和识别电话号码。

要从 PHONE _ STATE 意图操作中读取数字,请执行 您既需要 ABC0权限,也需要 READ_PHONE_STATE权限。 要从 onCallStateChanged()读取数字,现在只需要 READ_CALL_LOG权限。不再需要 READ_PHONE_STATE权限。

请使用以下代码。它将帮助您获得来电号码与其他呼叫细节。

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

只是为了更新 Gabe Sechan 的回答。如果您的清单请求对 READ _ CALL _ LOG 和 READ _ PHONE _ STATE 的权限,onReceive 将调用 两次。其中一个包含 EXTRA _ INCOMING _ NUMBER,而另一个没有。你必须测试哪个有它,它可以以任何顺序发生。

Https://developer.android.com/reference/android/telephony/telephonymanager.html#action_phone_state_changed

你需要一个用于 ACTION_PHONE_STATE_CHANGED的 BroadcastReceiver 每当电话状态从空闲状态、响铃状态、脱钩状态改变时,这个接收器就会呼叫你的接收器,这样就可以从以前的值和新的值中检测到这是否是一个传入/传出呼叫。

所需的许可如下:

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

但是如果您还想在该广播中接收 EXTRA _ INCOMING _ NUMBER,则需要另一个权限: “ android.permission on.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"]

额外的结果可能是:

如果你的电话在响

如果你正在和某人交谈(来电或来电) 电话)

IDLE-> 如果呼叫结束(呼入或呼出呼入)

使用 PHONE _ STATE 广播时,我们不需要使用 PROCESS _ OUTgoing _ CALLS 权限或不推荐的 NEW _ OUTgoing _ CALL 操作。

我修复了 Gabe Sechan 回答,我使用了下面的代码,它工作正常。 我注意到当一个接收器意图有“ 输入 _ 号码”键,我可以得到电话号码。所以我过滤了传入的意图,并使用 EXTRA _ INCOMING _ NUMBEREXTRA _ PHONE _ NUMBER来获得电话号码。

public class ChangeCallStateListener extends BroadcastReceiver {


private static String lastState = TelephonyManager.EXTRA_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) {
Log.d("CallObserver", "CallReceiver is starting ....");


List<String> keyList = new ArrayList<>();
Bundle bundle = intent.getExtras();
if (bundle != null) {
keyList = new ArrayList<>(bundle.keySet());
Log.e("CallObserver", "keys : " + keyList);
}


if (keyList.contains("incoming_number")) {
String phoneState = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String phoneIncomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
String phoneOutgoingNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);


String phoneNumber = phoneOutgoingNumber != null ? phoneOutgoingNumber : (phoneIncomingNumber != null ? phoneIncomingNumber : "");


if (phoneState != null && phoneNumber != null) {
if (lastState.equals(phoneState)) {
//No change, debounce extras
return;
}
Log.e("CallObserver", "phoneState = " + phoneState);
if (TelephonyManager.EXTRA_STATE_RINGING.equals(phoneState)) {
isIncoming = true;
callStartTime = new Date();
//
lastState = TelephonyManager.EXTRA_STATE_RINGING;
if (phoneNumber != null) {
savedNumber = phoneNumber;
}




onIncomingCallStarted(context, savedNumber, callStartTime);
} else if (TelephonyManager.EXTRA_STATE_IDLE.equals(phoneState)) {


if (lastState.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
//
lastState = TelephonyManager.EXTRA_STATE_IDLE;
onMissedCall(context, savedNumber, callStartTime);
} else {
if (isIncoming) {
//
lastState = TelephonyManager.EXTRA_STATE_IDLE;
onIncomingCallEnded(context, savedNumber, callStartTime, new Date());
} else {
//
lastState = TelephonyManager.EXTRA_STATE_IDLE;
Log.d("CallObserver", "onOutgoingCallEnded called !! : ");
onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());
}


}
} else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(phoneState)) {
if (lastState.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
isIncoming = true;
} else {
isIncoming = false;
}
callStartTime = new Date();
savedNumber = phoneNumber;
//
lastState = TelephonyManager.EXTRA_STATE_OFFHOOK;
onOutgoingCallStarted(context, savedNumber, callStartTime);
}
}
}


}




protected void onIncomingCallStarted(Context ctx, String number, Date start) {
Log.d("CallObserver", "onIncomingCallStarted  :  " + " number is  : " + number);
}


protected void onOutgoingCallStarted(Context ctx, String number, Date start) {
Log.d("CallObserver", "onOutgoingCallStarted  :  " + " number is  : " + number);
}


protected void onIncomingCallEnded(Context context, String number, Date start, Date end) {
}


protected void onOutgoingCallEnded(Context context , String number, Date start, Date end) {
}


protected void onMissedCall(Context context, String number, Date start) {
}


}
  • 不要忘记获得运行时许可。

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

请参考 Gabe Sechan的答案。如前所述,对于 Outgoing 调用,我们有以下状态更改: IDLE-> OffHOOK-> IDLE。在 Gabe 的原始答案中,savedNumber只有在电话状态变成 RINGING 时才会设置,而对于外拨电话则不会如此。当电话状态变为 OffHOOK 时,也设置 savedNumber的一个小修复:

case TelephonyManager.CALL_STATE_OFFHOOK:
if(lastState != TelephonyManager.CALL_STATE_RINGING){
//IDLE to OFFHOOK for example.
isIncoming = false;
callStartTime = new Date();
savedNumber = number;
onOutgoingCallStarted(context, savedNumber, callStartTime);
}
...

此修复程序允许将拨号传递给传出呼叫方法,方式与将传入号码传递给传入呼叫或未接呼叫方法的方式相同。

黑客警报:)

如果您只对传入呼叫事件感兴趣,可以考虑使用 AudioManager 并监听焦点更改。 优点-不需要许可。 缺点-不会在静音模式下工作... 在这种情况下,我们将增加来电的音量到最低限度,仍然得到音频焦点事件。

 /**
* Register a callback to [AudioManager] to identify an incoming call.
*/
private fun registerAudioFocusChangeListener(){
val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
val incomingCallVolume = audioManager.getStreamVolume(AudioManager.STREAM_RING)
if(incomingCallVolume == 0) {
// Hack Alert :)
// The user has muted the phone calls, if we still want to intercept the event,
// we set the volume of the incoming call to Minumum otherwise we will not get
// Audio focus event...
try {
audioManager.adjustVolume(
AudioManager.ADJUST_UNMUTE,
AudioManager.FLAG_ALLOW_RINGER_MODES
)
audioManager.setStreamVolume(
AudioManager.STREAM_RING,
audioManager.getStreamMinVolume(AudioManager.STREAM_RING),
0
);
} catch (e : SecurityException){
// DND (Don't Disturb Mode) is probably ON, we are not allowed to set the volume
//  in this scenario, But in this case no incoming call is possible anyway.
}
}
val requestBuilder = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
requestBuilder.setOnAudioFocusChangeListener { _ ->


Handler(Looper.getMainLooper()).postDelayed({
val mode = audioManager.mode
if(mode == AudioManager.MODE_RINGTONE || mode == AudioManager.MODE_IN_CALL){
//Ring Ring, do your thing
}
}, 100)
}
audioManager.requestAudioFocus(requestBuilder.build())
}