--- 作者 zuhui.zhang
安卓7.0原生系统增加了在framework层拦截黑名单来电和短信,但不会将数据保存到数据库,因此无法查看到被拦截的来电和短信。在安卓7.0之前,黑名单的短信默认是不会拦截的,为了实现黑名单短信拦截功能,需要对短信数据库表中的字段新增特殊的值,以便标记黑名单短信。以下具体说明下笔者对于MTK方案里的短信应用中拦截短彩信的实现方法。
涉及到的类:
com.android.mms.transaction.SmsReceiverService:短信接收服务类,
MyBlacklistManager:新创建的类,用于判断号码是否在黑名单、添加号码到黑名单、移除号码。
a) 实现思想:
在SmsReceiverService. handleSmsReceived()中,判断新来短信的号码是否是在黑名单中,如果是,则将Sms.READ设为1,同时将Sms.TYPE设为MyBlacklistManager. MESSAGE_TYPE_INTERCEPTED=7,然后保存到短信收件箱。要查看拦截短信时,只要查询数据库过滤出Sms.TYPE=7的短信,则为被拦截的黑名单短信。
b) 具体实现方法:
插入拦截字段:在SmsReceiverService .handleSmsReceived()中,在insertMessage()->storeMessage()函数中判断是否是黑名单,若是,则在sms表的type字段插入拦截类型的值(MESSAGE_TYPE_INTERCEPTED),read字段设为1:防止在launcher上显示未读短信数量,并MyBlacklistManager类使用一个布尔型变量记录已经成功拦截短信。
只通知被拦截的短信:在handleSmsReceived中,在insertMessage()调用之后,通过调用MyBlacklistManager中的autoReject()判断号码是否在黑名单列表中,如果是则只发出通知(隐藏部分信息),但是不会亮屏、发出通知音和振动。
其中autoReject()方法和方法中用到的变量如下:
// blacklist table uri
// private static final Uri BLACK_LIST_URI =Uri.parse("content://reject/list");// for android 4.4 to 5.x
private static final Uri BLACK_LIST_URI = Uri.parse("content://com.cmcc.ccs.black_list");// for android 6.0
// table field name
private static final String REJECT_FIELD_NUMBER="PHONE_NUMBER";
/**
* check if the number should be rejected
* @param number the sms/mms recipient
* @param type reject type, inBlackListManager class had define
* @return the result that the currentnumber should be auto reject, true:in blacklist, or not in.
*/
public static boolean autoReject(Context context, String number, int type) {
System.out.println("autoReject number:" + number);
if(context == null)
return false;
try{
ContentResolver cr = context.getContentResolver();
Cursor cursor = cr.query(BLACK_LIST_URI, null,REJECT_FIELD_NUMBER+"=?", new String[]{number}, null);
if (cursor != null) {
if(cursor.getCount() > 0) {
cursor.close();
return true;
} else {
cursor.close();
return false;
}
}
} catch(Exception e) {
Log.e(TAG, "--autoRejecterror = " + e.getMessage() + ", e object=" + e);
return false;
}
}
c) Sms.TYPE各值的含义如下:
因为要查看黑名单短信,所以需要修改数据库sms表的type字段,type=1:表示是收到的短信,type=2:表示是发送出去的短信,type=7:表示收到的被拦截的短信(在会话、短信查看、黑名单查看界面需要用到这个字段)。
短信type字段所有值都包含在Sms类定义中,和数据库表sms中的type值对应,具体如下:
Sms.MESSAGE_TYPE_ALL=0,表示所有类型的短信;
Sms.MESSAGE_TYPE_INBOX=1表示是接收的短信;
Sms.MESSAGE_TYPE_SENT=2表示发送的短信;
Sms.MESSAGE_TYPE_DRAFT=3表示该短信是草稿;
Sms.MESSAGE_TYPE_OUTBOX=4表示在发件箱中的短信;
Sms.MESSAGE_TYPE_FAILED=5表示发送失败的短信;Sms.MESSAGE_TYPE_QUEUED=6表示在队列中的短信。
MyBlacklistManager. MESSAGE_TYPE_INTERCEPTED=7表示被拦截的短信,新增的值。
修改com.android.mms.transaction.MmsPushReceiveService和用于拦截彩信。彩信通知在transaction/NotificationTransaction,而且要修改util/DownloadManager,transaction/Observable,transaction/Observer、transaction/RetryScheduler、transaction/TransactionService几个类。
彩信接收流程MTK实现如下,主要涉及的包:com.android.mms.transaction。
a) PushReceiver类,从底层接收彩信:收到彩信时,PushReceiver执行doInBackground(),接收intent,同时解析key为“data”的字节数据;使用PduParser解析数据,得到GenericPdu的数据(pdu),然后得到短信类型,类型为MESSAGE_TYPE_NOTIFICATION_IND时,使用PduPersister中的persist()将彩信数据写到数据库中(主要涉及pdu和part表),同时启动TransactionService(putExtra:TransactionBundle.TRANSACTION_TYPE=Transaction.NOTIFICATION_TRANSACTION),实现下载彩信功能。
b) TransactionService类,和PushReceiver和NotificationTransaction沟通作用:执行onStartCommand()函数,发送消息到ServiceHandler类处理;调用handleMessage(),执行case EVENT_TRANSACTION_REQUEST--caseTransaction.NOTIFICATION_TRANSACTION,实例化NotificationTransaction类àprocessTransaction()àNotificationTransaction.process()/RetrieveTransaction.process(),前者是接收到彩信时执行下载动作(若打开自动下载彩信开关),后者是当彩信在接收时未下载时,用户点击下载后执行下载动作;
c) NotificationTransaction类,下载彩信多媒体文件:process()àrun()àSmsManager. downloadMultimediaMessage()下载彩信到手机,同时启动TransactionService 使用action:TransactionService.ACTION_TRANSACION_PROCESSED,此时执行TransactionService. onStartCommand()àServiceHandler.handleMessage(),case EVENT_TRANSACTION_PROCESSEDàhandleTransactionProcessed()àNotificationTransaction. notifyObservers()àTransactionService.update(),case TransactionState.SUCCESSàcase Transaction.NOTIFICATION_TRANSACTIONàMessagingNotification.blockingUpdateNewSmsMessageIndicator()发出通知,彩信接收过程结束。
彩信拦截思想及流程
1、 在PushReceiver.doInBackground()中,更新pdu表:Mms.READ字段设成1,防止黑名单联系人来的彩信在launcher界面短信图标上显示未读数量。
2、 在NotifficationTransaction.run()中,若彩信关闭自动下载彩信开关,则直接调用自定义的updateBlacklistField()更新pdu表中Mms.READ=1,Mms.MESSAGE_BOX= MyBlacklistManager.MESSAGE_BOX_INTERCEPTED(值等于6)表示此彩信属于黑名单彩信;接收彩信时,若彩信自动下载开关打开,则在彩信下载完成后,进入TransactionService.handleTransactionProcessed()中调用更新pdu表的操作(若没有打开自动下载彩信,则会在用户点击下载按钮后,执行更新pdu表操作),修改字段值,函数和updateBlacklistField()类似。
updateBlacklistField()函数实现如下:
private boolean mIsBlcakNumber= true;
/**
* for set msg_box as blacklist
*/
private voidupdateBlacklistField() {
// for reset mms msg_box field as blacklist
// (close auto download mms) when user click downloadbutton@{
if (mIsBlcakNumber) {
try {
ContentValues values = new ContentValues();
// mark as read prevent provider to notifylauncher unread
// count. but black message is distinguishis read or unread
values.put(Mms.READ, "1");
values.put(Mms.MESSAGE_BOX, MyBlacklistManager.MESSAGE_BOX_INTERCEPTED);
mContext.getContentResolver().update(mUri, values, null, null);
} catch (Exception e) {
Log.e(TAG, "--change intercepted blacklist mms error1=" + e.getMessage()
+ ", e object" + e);
}
}
// @}
}
3、 pdu表的msg_box字段各值的含义如下:
Mms.MESSAGE_BOX_ALL=0
Mms.MESSAGE_BOX_INBOX=1
Mms.MESSAGE_BOX_SENT=2
Mms.MESSAGE_BOX_DRAFTS=3
Mms.MESSAGE_BOX_OUTBOX=4
MyBlacklistManager.MESSAGE_BOX_INTERCEPTED=6,新增的值。
以上方法希望能给遇到相同需求的开发者一些启发。
引用查询资料出处
http://zhanglfat.iteye.com/blog/1453353
http://blog.csdn.net/hitlion2008/article/details/7166075
http://www.android100.org/html/201502/25/123115.html
http://blog.csdn.net/tjy1985/article/details/7228282