最近做一个关于来去电监听然后挂断发短信功能的项目,碰到不知如何判断去电是否接通的问题,多方查询,网上的答案不一而足,最后 ,在借鉴网上的答案和自己的修改后,得出解决方案记录如下:
判断来电是否接通
这个好判断。
1. 当为来电时,电话状态首先进入
TelephonyManager.CALL_STATE_RINGING 也就是
响铃 状态
2. 接通时 进入
TelephonyManager.CALL_STATE_OFFHOOK 状态,也就是接通状态
3. 当挂断时,进入
TelephonyManager.CALL_STATE_IDLE 状态 ,也就是挂断状态。
所以,我们只需判断电话状态由 RINGING—>OFFHOOK时,就可以知道电话接通了。
但是当我们是拨出电话时,一拨的时候电话就会处于OFFHOOK状态,接通之后也是OFFHOOK状态,那咋办呢??
判断去电是否接通
多方查询,最后通过查询
calllog 也就是通话记录的方法,来判断电话是否拨通!
- 本来我也对 calllog了解不多,这里给个传送门,不太了解的同学可以看看关于这方面的API 。
- 因为android平台上的通话记录是以Content Provider的形式存储在手机上的,因此你需要使用ContentResolver来查询通话记录,返回Cursor接口。
- 然后通过这个contentresolver 来查询通话记录的数据库 ,得到一个游标 cursor,然后通过这个游标得到我们想要的通话记录
- 然后就可以查询到通话记录中的duration ,这就是最关键的,当duration>0的时候就说明电话接通了哈哈哈是不是也不难?!
光说不练假把式 且看代码!
下面给出我整个类的代码,里面关于数据库啊什么的,各位就不用深究,关键看如何得到去电是否接通。
注释也较详细,各位有不懂,欢迎留言或私信
public class EndCallReceiver extends BroadcastReceiver {
private RefuseComeMsgDao refuseComeMsgDao;
private String content;
@Override
public void onReceive(final Context context, Intent intent) {
final String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
TelephonyManager tm = (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);
int phoneState = tm.getCallState();
switch (phoneState) {
case TelephonyManager.CALL_STATE_RINGING:
LogUtil.log("响铃!!!!");
context.getSharedPreferences("blacklist", MODE_PRIVATE).edit().putBoolean("iscome", true).commit();
context.getSharedPreferences("blacklist", MODE_PRIVATE).edit().putBoolean("offhook", false).commit();
if (isInBlackList(number, context) || DateUtil.isRefuse(context)) {
Class telephonyManagerClass = TelephonyManager.class;
try {
Method method = telephonyManagerClass.getDeclaredMethod("getITelephony", new Class[0]);
method.setAccessible(true);
ITelephony itelephony = (ITelephony) method.invoke(tm, new Object[]{});
itelephony.endCall();
context.getSharedPreferences("refuseTime", MODE_PRIVATE).edit()
.putBoolean("dorefuse", true)
.commit();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
case TelephonyManager.CALL_STATE_IDLE:
LogUtil.log("挂断!!");
SharedPreferences preferences = context.getSharedPreferences("blacklist", MODE_PRIVATE);
SharedPreferences preferences2 = context.getSharedPreferences("refuseTime", MODE_PRIVATE);
boolean iscome = preferences.getBoolean("iscome", false);
if (iscome) {
if (preferences2.getBoolean("dorefuse", false)) {
DaoSession daoSession = DBUtil.initDb(new GreenDaoContext());
refuseComeMsgDao = daoSession.getRefuseComeMsgDao();
RefuseComeMsg refuse1 = refuseComeMsgDao.queryBuilder().where(RefuseComeMsgDao.Properties.Type.eq("refuse")).build().unique();
if (refuse1 == null) {
content = "";
} else {
content = refuse1.getContent();
}
if (!content.equals("") && !content.equals("不发送")) {
sendSMS(number, content, context);
}
preferences2.edit().putBoolean("dorefuse", false).commit();
} else {
String content = doGetComeMsg();
if (!content.equals("不发送")) {
sendSMS(number, content, context);
}
preferences.edit().putBoolean("iscome", false).commit();
}
} else if (!iscome) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
boolean callLogState = getCallLogState(context,number);
if (callLogState) {
String content = doGetOutMsg();
if (!content.equals("") && !content.equals("不发送")) {
sendSMS(number, content, context);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
LogUtil.log("OFFHOOK");
break;
}
}
/**
* 获得当前的去电回复短信
* @return 当前设置的去电回复模板
*/
private String doGetOutMsg() {
String string;
DaoSession daoSession = DBUtil.initDb(GreenDaoContext.getInstance());
Database database = daoSession.getDatabase();
CurrentTemplateDaoDao currentTemplateDaoDao = daoSession.getCurrentTemplateDaoDao();
currentTemplateDaoDao.createTable(database, true);
CurrentTemplateDao out = currentTemplateDaoDao.queryBuilder().where(CurrentTemplateDaoDao.Properties.Type.eq("out")).build().unique();
if (out != null) {
string = out.getContent();
} else {
string = "不发送";
}
return string;
}
/**
* 获得当前的来电回复短信
* @return 当前设置的来电模板内容
*/
private String doGetComeMsg() {
String string;
DaoSession daoSession = DBUtil.initDb(GreenDaoContext.getInstance());
Database database = daoSession.getDatabase();
CurrentTemplateDaoDao currentTemplateDaoDao = daoSession.getCurrentTemplateDaoDao();
currentTemplateDaoDao.createTable(database, true);
CurrentTemplateDao come = currentTemplateDaoDao.queryBuilder().where(CurrentTemplateDaoDao.Properties.Type.eq("come")).build().unique();
if (come != null) {
string = come.getContent();
} else {
string = "不发送";
}
return string;
}
private boolean isInBlackList(String number, Context context) {
List blackLists = DBUtil.getBlackListDao().loadAll();
for (BlackList blackList : blackLists) {
if (blackList.getNumber().equals(number)) {
return true;
}
}
return false;
}
private void sendSMS(String phoneNum, String message, Context context) {
android.telephony.SmsManager smsManager = android.telephony.SmsManager.getDefault();
List divideContents = smsManager.divideMessage(message);
for (String text : divideContents) {
/**
* 参数4和5:
* sentIntent——如果不为空,当消息成功发送或失败这个PendingIntent就广播。结果代码是Activity.RESULT_OK表示成功,或RESULT_ERROR_GENERIC_FAILURE、RESULT_ERROR_RADIO_OFF、RESULT_ERROR_NULL_PDU之一表示错误。对应RESULT_ERROR_GENERIC_FAILURE,sentIntent可能包括额外的“错误代码”包含一个无线电广播技术特定的值,通常只在修复故障时有用。
* 每一个基于SMS的应用程序控制检测sentIntent。如果sentIntent是空,调用者将检测所有未知的应用程序,这将导致在检测的时候发送较小数量的SMS。
* deliveryIntent——如果不为空,当消息成功传送到接收者这个PendingIntent就广播。
*/
smsManager.sendTextMessage(phoneNum, null, text, null, null);
DBUtil.initDb(new GreenDaoContext()).getSendRecordDao().insert(new SendRecord(null, phoneNum, DateUtil.getDate(), message));
}
}
private boolean getCallLogState(Context context,String number) {
boolean isLink = false;
ContentResolver cr = context.getContentResolver();
PermissionChecker.checkSelfPermission(context, Manifest.permission.READ_CALL_LOG);
final Cursor cursor = cr.query(CallLog.Calls.CONTENT_URI,
new String[]{CallLog.Calls.NUMBER,CallLog.Calls.TYPE,CallLog.Calls.DURATION},
CallLog.Calls.NUMBER +"=?",
new String[]{number},
CallLog.Calls.DATE + " desc");
int i = 0;
while(cursor.moveToNext()){
if (i == 0) {
int durationIndex = cursor.getColumnIndex(CallLog.Calls.DURATION);
long durationTime = cursor.getLong(durationIndex);
if(durationTime > 0){
LogUtil.log("到这里了 这是if里 durationTime = "+durationTime);
isLink = true;
} else {
LogUtil.log("到这里了 这是else里");
isLink = false;
}
}
i++;
}
return isLink;
}
}
**代码中的获取电话状态是通过AIDL实现的。
代码不是啥完美的代码,有瑕疵也欢迎吐槽。
以上。**