Android来电监听
Posted 摸爬滚打的程序媛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android来电监听相关的知识,希望对你有一定的参考价值。
android 来电监听
⭐ 最近项目中有个需求是:监听手机来电,如果是来电号码是本地已存储的联系人,则显示本地联系人的名字;否则,就直接显示来电号码。
🖊🖊🖊因为这个需求平时遇到的少,所以这里记录一下🖊🖊🖊。
1 依据来电号码查询本地联系人
先来看看如何根据来电号码查询本地联系人呢?
1.1 权限
这里需要访问手机通讯录的权限READ_CONTACTS,分别在配置文件中静态申请以及代码中动态申请。
<!--读取手机通讯录-->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
动态权限申请在后面的代码中。
1.2 实现
/**
* 获取来电号码对应的联系人名称
* @param context 上下文
* @param phoneNumber 电话号码
* @return 联系人名称(如果来电号码没有对应联系人名称,则直接返回电话号码)
*/
public static String getIncomingCallName(Context context,String phoneNumber)
//格式化电话号码
if(phoneNumber == null)
return null;
phoneNumber = phoneNumber.trim().replace(" ","").replace("-","");
//是否查询到
boolean isSuccess = false;
String phoneName = null;
//联系人的Uri,也就是content://com.android.contacts/contacts
Uri uri = ContactsContract.Contacts.CONTENT_URI;
//指定获取_id和display_name两列数据,display_name即为姓名
String[] projection = new String[]
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME
;
//根据Uri查询相应的ContentProvider,cursor为获取到的数据集
Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
if (cursor != null && cursor.moveToFirst())
do
try
Long id = cursor.getLong(0);
//获取姓名
String name = cursor.getString(1);
//指定获取NUMBER这一列数据
String[] phoneProjection = new String[]
ContactsContract.CommonDataKinds.Phone.NUMBER
;
//根据联系人的ID获取此人的电话号码
Cursor phonesCursor = context.getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
phoneProjection,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + id,
null,
null);
//因为每个联系人可能有多个电话号码,所以需要遍历
if (phonesCursor != null && phonesCursor.moveToFirst())
do
String num = phonesCursor.getString(0);
num = num.trim().replace(" ","").replace("-","");
if(num.equals(phoneNumber))
//查询到号码
isSuccess = true;
phoneName = name;
break; //退出
while (phonesCursor.moveToNext());
//已经找到,退出大循环
if(isSuccess)
break;
catch (Exception e)
e.printStackTrace();
while (cursor.moveToNext());
//如果来电号码没有对应联系人名称,则直接返回电话号码
if(isSuccess)
return phoneName;
else
return phoneNumber;
2 来电监听方法(有两种)
监听手机来电的方法一般有两种:使用系统广播监听 和 使用PhoneStateListener 监听器。
下面分别来讲解这两种方法的使用。
2.1 系统广播监听
2.1.1 权限
通过监听广播的方式来监听来电时,必须需要以下两个权限.READ_PHONE_STATE和READ_CALL_LOG,因为是危险权限,除了静态表明外,Android6.0以后还必须要动态申请。
<!--读取手机状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!--读取手机通话记录:Android 9.0没有此权限,获取不到来电号码-->
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<!--读取手机通讯录-->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
动态申请权限(此处使用郭霖的开源库PermissionX权限库进行权限申请)
//PermissionX权限库
implementation 'com.permissionx.guolindev:permissionx:1.4.0'
//广播监听方式监听来电,需要检测的权限
private void checkBroadcastCallPermission()
PermissionX.init(this)
.permissions( //传入需要申请的权限
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.READ_CONTACTS,
Manifest.permission.READ_CONTACTS)
.onExplainRequestReason(new ExplainReasonCallbackWithBeforeParam()
@Override
public void onExplainReason(ExplainScope scope, List<String> deniedList, boolean beforeRequest)
scope.showRequestReasonDialog(deniedList, "来电监听需要授予'获取设备信息和访问手机通话记录'的权限,依据来电号码查询联系人需要'读取手机通讯录'权限,否则应用无法正常使用", "我已明白");
)
.onForwardToSettings(new ForwardToSettingsCallback()
@Override
public void onForwardToSettings(ForwardScope scope, List<String> deniedList)
scope.showForwardToSettingsDialog(deniedList, "您需要去应用程序设置当中手动开启权限", "我已明白");
)
.request(new RequestCallback()
@Override
public void onResult(boolean allGranted, List<String> grantedList, List<String> deniedList)
if (allGranted)
Log.d(TAG, "所有申请的权限都已通过");
else
Toast.makeText(MainActivity.this, "您拒绝了如下权限:" + deniedList, Toast.LENGTH_SHORT).show();
);
2.1.2 注册电话状态系统广播接收器
//电话状态的广播
private final String PHONE_STATE_ACTION = "android.intent.action.PHONE_STATE";
//自定义广播接收器
private BroadcastReceiver comingCallBR = new BroadcastReceiver()
@Override
public void onReceive(Context context, Intent intent)
Log.d(TAG, "onReceive(): action = " + intent.getAction());
if(intent.getAction() != null
&& intent.getAction().equals(PHONE_STATE_ACTION))
//电话状态
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
Log.d(TAG, "onReceive(): phone state = " + state);
// 电话正在响铃,即来电
if (state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING))
//正在响铃...
//来电号码
String comingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if(comingNumber == null ||comingNumber.isEmpty())
return;
Log.d(TAG, "onReceive(): 来电号码 = " + comingNumber);
if(comingCallListener != null)
comingCallListener.onCalling(curTimeToFormatNoYearMills(),comingNumber,null);
else if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_OFFHOOK))
//正在通话...
else if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE))
//电话挂断
;
//注册监听来电的广播接收者
public boolean initBroadcastReceiver()
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(PHONE_STATE_ACTION);
registerReceiver(comingCallBR, intentFilter);
return true;
//注销广播
public boolean unregisterReceiver()
unregisterReceiver(comingCallBR);
return true;
2.2 PhoneStateListener 监听器
2.2.1 权限
通过PhoneStateListener 监听器的方式来监听来电时,只需要一个权限READ_CALL_LOG,因为是危险权限,除了静态表明外,Android6.0以后同样需要动态申请。
<!--读取手机通话记录:Android 9.0没有此权限,获取不到来电号码-->
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<!--读取手机通讯录-->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
//PhoneStateListener监听方式监听来电,需要检测的权限
private void checkPhoneStateListenerCallPermission()
PermissionX.init(this)
.permissions( //传入需要申请的权限
Manifest.permission.READ_CALL_LOG,
Manifest.permission.READ_CONTACTS)
.onExplainRequestReason(new ExplainReasonCallbackWithBeforeParam()
@Override
public void onExplainReason(ExplainScope scope, List<String> deniedList, boolean beforeRequest)
scope.showRequestReasonDialog(deniedList, "来电监听需要授予'访问手机通话记录'的权限,依据来电号码查询联系人需要'读取手机通讯录'权限,否则应用无法正常使用", "我已明白");
)
.onForwardToSettings(new ForwardToSettingsCallback()
@Override
public void onForwardToSettings(ForwardScope scope, List<String> deniedList)
scope.showForwardToSettingsDialog(deniedList, "您需要去应用程序设置当中手动开启权限", "我已明白");
)
.request(new RequestCallback()
@Override
public void onResult(boolean allGranted, List<String> grantedList, List<String> deniedList)
if (allGranted)
Log.d(TAG, "所有申请的权限都已通过");
Toast.makeText(MainActivity.this, "权限已授予", Toast.LENGTH_SHORT).show();
//权限授予成功之后,开启广播监听
ComingCallListenManager.getManager(MainActivity.this).initBroadcastReceiver();
else
Toast.makeText(MainActivity.this, "您拒绝了如下权限:" + deniedList, Toast.LENGTH_SHORT).show();
);
2.2.2 初始化PhoneStateListener
PhoneStateListener监听器类,用于监视设备上特定电话状态的变化,包括服务状态、信号强度、消息等待指示器(语音邮件)等。
TelephonyManager 提供对设备上电话服务的信息的访问。应用程序可以使用该类中的方法来确定电话服务和状态,以及访问某些类型的订阅者信息。应用程序还可以注册侦听器来接收电话状态更改的通知。
// 电话管理者对象
private TelephonyManager mTelephonyManager;
// 电话状态监听者
private PhoneStateListener mPhoneStateListener;
//初始化PhoneStateListener
public boolean initPhoneStateListener()
mTelephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
mPhoneStateListener = new PhoneStateListener()
@Override
public void onCallStateChanged(int state, String phoneNumber)
switch(state)
case TelephonyManager.CALL_STATE_IDLE:
//电话挂断
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
//正在通话...
break;
case TelephonyManager.CALL_STATE_RINGING:
//正在响铃...
if(phoneNumber == null ||phoneNumber.isEmpty())
return;
Log.d(TAG, "onCallStateChanged(): 来电号码 = " + phoneNumber);
if(comingCallListener != null)
comingCallListener.onCalling(curTimeToFormatNoYearMills(),phoneNumber,null);
break;
;
//开启监听
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
return true;
public boolean cancelPhoneStateListener()
// 取消来电的电话状态监听服务
if (mTelephonyManager != null && mPhoneStateListener != null)
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
return true;
return false;
3 完整Demo
下载地址:https://download.csdn.net/download/qq_38950819/60265473
以上是关于Android来电监听的主要内容,如果未能解决你的问题,请参考以下文章