接收新信息,在会话中看不到(thread表数据插入/更新失败)
分析原因:收到短信,sms表插入信息,触发器会自动更新thread表,更新失败导致一直有一条未读信息数量显示,但在会话列表中却看不到。
(偶现,低概率。 解决方法:接收新信息插入后,立即查询thread表,如果刚刚的信息查不到,则再次手动更新)
android\packages\providers\TelephonyProvider\src\com\android\providers\telephony\MmsSmsDatabaseHelper.java中定义了触发器
private void createCommonTriggers(SQLiteDatabase db) {
// Updates threads table whenever a message is added to sms.
db.execSQL("CREATE TRIGGER sms_update_thread_on_insert AFTER INSERT ON sms " +
SMS_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE);
// Updates threads table whenever a message in sms is updated.
db.execSQL("CREATE TRIGGER sms_update_thread_date_subject_on_update AFTER" +
" UPDATE OF " + Sms.DATE + ", " + Sms.BODY + ", " + Sms.TYPE +
" ON sms " +
SMS_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE);
// Updates threads table whenever a message in sms is updated.
db.execSQL("CREATE TRIGGER sms_update_thread_read_on_update AFTER" +
" UPDATE OF " + Sms.READ +
" ON sms " +
"BEGIN " +
SMS_UPDATE_THREAD_READ_BODY +
"END;");
// TODO Add triggers for SMS retry-status management.
// Update the error flag of threads when the error type of
// a pending MM is updated.
db.execSQL("CREATE TRIGGER update_threads_error_on_update_mms " +
" AFTER UPDATE OF err_type ON pending_msgs " +
" WHEN (OLD.err_type < 10 AND NEW.err_type >= 10)" +
" OR (OLD.err_type >= 10 AND NEW.err_type < 10) " +
"BEGIN" +
" UPDATE threads SET error = " +
" CASE" +
" WHEN NEW.err_type >= 10 THEN error + 1" +
" ELSE error - 1" +
" END " +
" WHERE _id =" +
" (SELECT DISTINCT thread_id" +
" FROM pdu" +
" WHERE _id = NEW.msg_id); " +
"END;");
// Update the error flag of threads after a text message was
// failed to send/receive.
db.execSQL("CREATE TRIGGER update_threads_error_on_update_sms " +
" AFTER UPDATE OF type ON sms" +
" WHEN (OLD.type != 5 AND NEW.type = 5)" +
" OR (OLD.type = 5 AND NEW.type != 5) " +
"BEGIN " +
" UPDATE threads SET error = " +
" CASE" +
" WHEN NEW.type = 5 THEN error + 1" +
" ELSE error - 1" +
" END " +
" WHERE _id = NEW.thread_id; " +
"END;");
}
Ril层接收新信息会通过Framework发通知——android.provider.Telephony.SMS_DELIVER
APP层MMS开始处理com.android.mms.transaction.PrivilegedSmsReceiver接收广播,
com.android.mms.transaction.SmsReceiverService调用handleSmsReceived(intent, error)方法,
————>saveMessageToPhone(msgs, error, format)————> insertMessage(this, msgs, error, format)
————>storeMessage(context, msgs, error);
storeMessage(context, msgs, error)方法最后,增加查询thread表,确认信息更新是否成功,如果thread表信息更新失败,手动更新.
private Uri storeMessage(Context context, SmsMessage[] msgs, int error) {
// Check to see whether short message count is up to 2000 for cmcc
if (MessageUtils.checkIsPhoneMessageFull(this)) {
return null;
}
SmsMessage sms = msgs[0];
// Store the message in the content provider.
ContentValues values = extractContentValues(sms);
values.put(Sms.ERROR_CODE, error);
values.put(Sms.PHONE_ID, SubscriptionManager.getPhoneId(sms.getSubId()));
int pduCount = msgs.length;
if (pduCount == 1) {
// There is only one part, so grab the body directly.
values.put(Inbox.BODY, replaceFormFeeds(sms.getDisplayMessageBody()));
} else {
// Build up the body from the parts.
StringBuilder body = new StringBuilder();
for (int i = 0; i < pduCount; i++) {
sms = msgs[i];
if (sms.mWrappedSmsMessage != null) {
body.append(sms.getDisplayMessageBody());
}
}
values.put(Inbox.BODY, replaceFormFeeds(body.toString()));
}
// Make sure we've got a thread id so after the insert we'll be able to delete
// excess messages.
Long threadId = values.getAsLong(Sms.THREAD_ID);
String address = values.getAsString(Sms.ADDRESS);
// Code for debugging and easy injection of short codes, non email addresses, etc.
// See Contact.isAlphaNumber() for further comments and results.
// switch (count++ % 8) {
// case 0: address = "AB12"; break;
// case 1: address = "12"; break;
// case 2: address = "Jello123"; break;
// case 3: address = "T-Mobile"; break;
// case 4: address = "Mobile1"; break;
// case 5: address = "Dogs77"; break;
// case 6: address = "****1"; break;
// case 7: address = "#4#5#6#"; break;
// }
if (!TextUtils.isEmpty(address)) {
Contact cacheContact = Contact.get(address,true);
if (cacheContact != null) {
address = cacheContact.getNumber();
}
} else if (TextUtils.isEmpty(address)
&& getResources().getBoolean(R.bool.def_hide_unknown_sender)) {
values.put(Sms.ADDRESS, "");
} else {
address = getString(R.string.unknown_sender);
values.put(Sms.ADDRESS, address);
}
if (((threadId == null) || (threadId == 0)) && (address != null)) {
threadId = Conversation.getOrCreateThreadId(context, address);
values.put(Sms.THREAD_ID, threadId);
}
ContentResolver resolver = context.getContentResolver();
Uri insertedUri = SqliteWrapper.insert(context, resolver, Inbox.CONTENT_URI, values);
// Now make sure we're not over the limit in stored messages
Recycler.getSmsRecycler().deleteOldMessagesByThreadId(context, threadId);
MmsWidgetProvider.notifyDatasetChanged(context);
//---add by antoon ----------------------------------------------------------------------------------------------------
//query thread to check if thread update or create successfully, if not update here
StringBuilder sbUri = new StringBuilder(3);
sbUri.append("content://mms-sms/conversations/").append(threadId).append("/recipients");
Cursor curosr = resolver.query(Uri.parse(sbUri.toString()),null,null,null,null);
Log.i("antoon", "SmsReceiverService, --> storeMessage , curosr = "+curosr);
if(curosr == null || curosr.getCount()==0){
SqliteWrapper.insert(context, resolver, Telephony.Threads.CONTENT_URI, values);//------手动更新thread表
}else{
Log.d("antoon", "SmsReceiverService, --> storeMessage , curosr.getCount = " + curosr.getCount());
}
//---end add by antoon -------------------------------------------------------------------------------------------------
return insertedUri;
}
TelephonyProvider中增加相应的数据库处理。 android\packages\providers\TelephonyProvider\src\com\android\providers\telephony\MmsSmsProvider.java中增加 insert/update 处理
@Override
public Uri insert(Uri uri, ContentValues values) {
if (URI_MATCHER.match(uri) == URI_PENDING_MSG) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long rowId = db.insert(TABLE_PENDING_MSG, null, values);
return Uri.parse(uri + "/" + rowId);
}
//------ add by antoon
else if(URI_MATCHER.match(uri) == URI_CONVERSATIONS){
Log.i("antoon", "MmsSmsProvider -> insert, URI_CONVERSATIONS");
insertThreadsIfDataLost(values);
return null;
} //------ end add by antoon
throw new UnsupportedOperationException(NO_DELETES_INSERTS_OR_UPDATES + uri);
}
//------add by antoon, create thread data if thread trigger fail
public void insertThreadsIfDataLost(ContentValues values) {
long _id = values.getAsLong(Sms.THREAD_ID);
long date = values.getAsLong(Sms.DATE);
String snippet = values.getAsString(Sms.BODY);
String address = values.getAsString(Sms.ADDRESS); //create a new thread id with new msg address, then update threadId to _id
List<String> list = new ArrayList<String>();
list.add(address);
Cursor cursor = getThreadId(list, false);//------这里的查询会判断threadId是否存在,如果不存在则创建threadId新数据,如果存在则直接返回。
cursor.moveToFirst();
long threadId = cursor.getLong(0);
cursor.close();
/*
String updateSql = "UPDATE threads SET date = ?, snippet = ?, snippet_cs = 0, read=0, "
+ "message_count = (SELECT COUNT(sms._id) FROM sms WHERE sms.thread_id = ? AND sms.type!= 3) + "
+"(SELECT COUNT(pdu._id) FROM pdu WHERE pdu.thread_id = ? AND (m_type=132 OR m_type=130 OR m_type=128) AND msg_box!= 3)"
+ " WHERE threads._id = ?";
*/ StringBuilder sqlSb = new StringBuilder(14);
sqlSb.append("UPDATE threads SET _id =").append(_id)
.append(", date =").append(date)
.append(", snippet ='").append(snippet)
.append("', snippet_cs = 0, read=0, ")
.append("message_count = (SELECT COUNT(sms._id) FROM sms WHERE sms.thread_id = ").append(threadId)
.append(" AND sms.type!= 3) + (SELECT COUNT(pdu._id) FROM pdu WHERE pdu.thread_id =").append(threadId)
.append(" AND (m_type=132 OR m_type=130 OR m_type=128) AND msg_box!= 3) WHERE threads._id = ").append(threadId)
; SQLiteDatabase db = mOpenHelper.getReadableDatabase();
db.execSQL(sqlSb.toString()); Log.i("antoon", "sqlSb = " + sqlSb);
}
//------end add by antoon
接收新信息,在会话中看不到(thread表数据插入/更新失败)的更多相关文章
- android6.0锁屏界面接收新通知处理流程
灭屏状态下,接收新信息,屏幕会半亮显示通知流程: 1,应用构造notification后,传给NotificationManager,而后进入NotificationManagerService处理. ...
- ABAP 动态备份自建表数据到新表(自建表有数据的情况下要改字段长度或者其他)
当abaper开发好一个程序给用户使用一段时间后,发现某个字段的长度需要修改,但数据库表中已经存在很多数据,冒然直接改表字段可能会导致数据丢失,这种问题的后果可能非常严重. 所以我想到先复制出一个新表 ...
- MQTT的学习研究(四)moquette-mqtt 的使用之mqtt Blocking API客户端订阅并接收主题信息
在上面两篇关于mqtt的broker的启动和mqtt的服务端发布主题信息之后,我们客户端需要订阅相关的信息并接收相关的主题信息. package com.etrip.mqtt; import java ...
- 记一次PHP实现接收邮件信息(我这里测试的腾讯企业邮件)
PHP实现接收邮件信息(我这里测试的腾讯企业邮件) , 其他的类型的没有测,应该只要更换pop3地址 端口号就可以. 代码如下(代码参考网络分享): <?php //此处查看链接状态 heade ...
- 【多端应用开发系列1.1.1 —— Android:使用新浪API V2】服务器Json数据处理——Json数据概述
[前白] 一些基础的东西本系列中就不再详述了,争取尽量写些必不可少的技术要点. 由于本系列把Web Service 构建放到了第二部分,Android项目就采用新浪微博API v2作为服务器端. [原 ...
- MySQL触发器初试:当A表插入新记录,自动在B表中插入相同ID的记录
今天第一次用MySQL的触发器,怕忘了,赶紧写篇博客记录一下. 废话不说,先上语法: 1 CREATE TRIGGER trigger_name 2 { BEFORE | AFTER } { INSE ...
- SQL语句 在一个表中插入新字段
SQL语句 在一个表中插入新字段: alter table 表名 add 字段名 字段类型 例: alter table OpenCourses add Audio varchar(50)alter ...
- mysql复制表数据或表结构到新表中
MySQL复制表数据到新表的几个步骤. 1.MySQL复制表结构及数据到新表 CREATE TABLE new_table SELECT * FROM old_table; 2.只复制表结构到新表 C ...
- 会话的保持和form表单
会话的保持和form表单 cookie 设置cookie from django.shortcuts import render, HttpResponse, redirect, reverse de ...
随机推荐
- rabbitMQ+yii2 使用
安装rabbitMQ 见此文章 http://www.cnblogs.com/zxxyx/p/6229613.html 安装好之后 出现此目录: 然后需要yii里面进行载入: 这个目录下面: 加上这个 ...
- dynamic 的使用 待续
Dynamic 使用场景之一 : 替代反射 class Me { public string Blog { get; set; } public string GetName() { return&q ...
- css之页面两列布局
两列布局:左边固定,后边自适应 第一种方法:左边的div左浮动或者是绝对定位,右边的div加margin-left:左边div的宽度 html部分 <div class="left&q ...
- maven增加自定义jar包
1.博客来源: http://www.cnblogs.com/leiOOlei/p/3356834.html 导入平台SDK的方法 mvn install:install-file -DgroupId ...
- 如何优化cocos2d程序的内存使用和程序大小
在我完成第一个游戏项目的时候,我深切地意识到"使用cocos2d来制作游戏的开发者们,他们大多会被cocos2d的内存问题所困扰".而我刚开始接触cocos2d的时候,社区里面的人 ...
- Python: 字典的基本操作
字典是Python里唯一的映射类型.字典是可变的.无序的.大小可变的键值映射,有时候也称为散列表或关联数组. 例子在下面: dic = {"apple":2, "oran ...
- MySQL分区表管理
RANGE,LIST分区管理 1:为未分区表创建分区 ALTER TABLE trb3 PARTITION BY KEY(id) PARTITIONS 2; 2:删除某个分区的数据 ALTER TAB ...
- Python语法三
1. from os.path import exists import 了又一个很好用的命令 exists.这个命令将文件名字符串作为参 数,如果文件存在的话,它将返回 True,否则将返回 Fal ...
- XproerUI控件工厂代码优化-使用C++11特性优化
优化前的代码,比较冗余,通常实现一个工厂类的创建器需要三个步骤. 代码截图: 优化后的代码,更简洁,对开发人员更加友好,实现一个工厂类创建器只需要一个步骤. 代码截图:
- 线性代数和numpy——黑板客老师课程学习
一.代数是什么 代数->数的抽象表示->向量空间(线性空间) 线代->线性代数 关系: 向量空间之间和内部转换是通过线性变换. 实数——一维空间的点 复数——二维空间的点 如果两个向 ...