? 最近项目中有个需求是:监听手机来电,如果是来电号码是本地已存储的联系人,则显示本地联系人的名字;否则,就直接显示来电号码。
🖊🖊🖊因为这个需求平时遇到的少,所以这里记录一下🖊🖊🖊。
1 依据来电号码查询本地联系人
先来看看如何根据来电号码查询本地联系人呢?
1.1 权限
这里需要访问手机通讯录的权限READ_CONTACTS,分别在配置文件中静态申请以及代码中动态申请。
<uses-permission android:name="android.permission.READ_CONTACTS"/>
动态权限申请在后面的代码中。
1.2 实现
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 uri = ContactsContract.Contacts.CONTENT_URI;
String[] projection = new String[]{
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME
};
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);
String[] phoneProjection = new String[]{
ContactsContract.CommonDataKinds.Phone.NUMBER
};
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"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
动态申请权限(此处使用郭霖的开源库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以后同样需要动态申请。
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
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;
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
|