短信 thread 表 以及 在Telephony.Threads
1.表中字段
_id INTEGER PRIMARY_KEY 主键ID 系统生成
date INTEGER The date at which the thread was created. 日期
message_count INTEGER The message count of the thread. 该会话的短信总条数
recipient_ids TEXT canonical_addresses的主键 FK
snippet TEXT The snippet of the latest message in the thread. 在最前面显示的短信
snippet_cs INTEGER The charset of the snippet.
read INTEGER Indicates whether all messages of the thread have been read. 已读为1,未读为0
type INTEGER Type of the thread, either Threads.COMMON_THREAD or Threads.BROADCAST_THREAD. push的短信为0
error INTEGER Indicates whether there is a transmission error in the thread. 有错误为1,没有为0
has_attachment INTEGER Indicates whether this thread contains any attachments. 没有为1,有为0
2.
2.1.生成会话 id
//系统提供的方法
public static long getOrCreateThreadId(Context context, String recipient)
2.2查询threads 表
// 下面这个方法亲测可以查询出来 threads 表中的全部数据
getContentResolver().query(Uri.parse("content://sms/"), new String[]{"* from threads --"}, null, null, null);
//按照上面的方式 我试了一下查询sms 表,也是可以查询出来的
getContentResolver().query(Uri.parse("content://sms/"), new String[]{"* from threads --"}, null, null, null);
这个的原理应该是 后面的 – 将后面拼接的所有 sql 都注释掉了,所以只能执行前面的 selec * from 了
2.3其中短信模块刚进入时的会话列表界面其实也是 查询的 threads表进行显示的
在 com.android.sms.data.Conversation.java 中
android.provider.telephony.Thread;
//短信中对 uri做了参数处理
uri = Threads.CONTENT_URI.buildUpon().appendQueryParameter(“simple”,”true”).build();
// 其实直接用 thread URI 就可以查询出来,已验证
getContentResolver().query(Threads.CONTENT_URI, new String[]{“id, xx,xx,xx”}, null, null, “date desc”);
- 定义Telephony.MmsSms类。
Contains all MMS and SMS messages.
- 在Telephony.MmsSms中定义了一些URI常量。
public static final Uri CONTENT_URI = Uri.parse(“content://mms-sms/”);
public static final Uri CONTENT_CONVERSATIONS_URI = Uri.parse(
“content://mms-sms/conversations”);
public static final Uri CONTENT_FILTER_BYPHONE_URI = Uri.parse(
“content://mms-sms/messages/byphone”);
public static final Uri CONTENT_UNDELIVERED_URI = Uri.parse(
“content://mms-sms/undelivered”);
public static final Uri CONTENT_DRAFT_URI = Uri.parse(
“content://mms-sms/draft”);
public static final Uri CONTENT_LOCKED_URI = Uri.parse(
“content://mms-sms/locked”);
public static final Uri SEARCH_URI = Uri.parse(
“content://mms-sms/search”);
上面的方式是之前的, 发现网上很多说这个方式在一些机型上有问题,
发现很多东西还是要去看源码
- 首先是查询 threads 表的内容
源码位置: packages/providers/TelephonyProvider/src/com/android/providers/telephony/TelephonyBackupAgent.java
其实还有好多有用的方法可以在这个类中参考
1205 @VisibleForTesting
1206 static final Uri ALL_THREADS_URI =
1207 Telephony.Threads.CONTENT_URI.buildUpon().
1208 appendQueryParameter("simple", "true").build(); ----- 这是 URI 的拼接
1209 private static final int RECIPIENT_IDS = 1;
1210
1211 // Copied from packages/apps/Messaging/src/com/android/messaging/sms/MmsUtils.java.
1212 // NOTE: There are phones on which you can't get the recipients from the thread id for SMS
1213 // until you have a message in the conversation!
1214 private String getRawRecipientIdsForThread(final long threadId) {
1215 if (threadId <= 0) {
1216 return null;
1217 }
1218 final Cursor thread = mContentResolver.query(
1219 ALL_THREADS_URI,
1220 SMS_RECIPIENTS_PROJECTION, "_id=?", new String[]{String.valueOf(threadId)}, null); --- 这里是根据id查询,如果全查就不要带条件了
1221 if (thread != null) {
1222 try {
1223 if (thread.moveToFirst()) {
1224 // recipientIds will be a space-separated list of ids into the
1225 // canonical addresses table.
1226 return thread.getString(RECIPIENT_IDS);
1227 }
1228 } finally {
1229 thread.close();
1230 }
1231 }
1232 return null;
1233 }
Uri sAllThreadsUri =
Threads.CONTENT_URI.buildUpon().appendQueryParameter("simple", "true").build();
String[] ALL_THREADS_PROJECTION = {
Threads._ID, Threads.DATE, Threads.MESSAGE_COUNT, Threads.RECIPIENT_IDS,
Threads.SNIPPET, Threads.SNIPPET_CHARSET, Threads.READ, Threads.ERROR,
Threads.HAS_ATTACHMENT
};
cursor = cr.query( sAllThreadsUri, ALL_THREADS_PROJECTION , null ,null, "date DESC" );
- 更新threads表中的信息
源码位置:packages/providers/TelephonyProvider/src/com/android/providers/telephony/MmsSmsProvider.java
281 static {
282 URI_MATCHER.addURI(AUTHORITY, "conversations", URI_CONVERSATIONS); --- 短信界面会话
283 URI_MATCHER.addURI(AUTHORITY, "complete-conversations", URI_COMPLETE_CONVERSATIONS);
284
285 // In these patterns, "#" is the thread ID.
286 URI_MATCHER.addURI(
287 AUTHORITY, "conversations/#", URI_CONVERSATIONS_MESSAGES);
288 URI_MATCHER.addURI(
289 AUTHORITY, "conversations/#/recipients",
290 URI_CONVERSATIONS_RECIPIENTS);
291
292 URI_MATCHER.addURI(
293 AUTHORITY, "conversations/#/subject",
294 URI_CONVERSATIONS_SUBJECT);
295
296 // URI for obtaining all short message count
297 URI_MATCHER.addURI(AUTHORITY, "messagescount", URI_MESSAGES_COUNT);
298
299 // URI for deleting obsolete threads.
300 URI_MATCHER.addURI(AUTHORITY, "conversations/obsolete", URI_OBSOLETE_THREADS);
301
302 URI_MATCHER.addURI(AUTHORITY, "search-message", URI_SEARCH_MESSAGE);
303
304 URI_MATCHER.addURI(
305 AUTHORITY, "messages/byphone/*",
306 URI_MESSAGES_BY_PHONE);
307
308 // In this pattern, two query parameter names are expected:
309 // "subject" and "recipient." Multiple "recipient" parameters
310 // may be present.
311 URI_MATCHER.addURI(AUTHORITY, "threadID", URI_THREAD_ID); --根据 thread_id do
312
313 URI_MATCHER.addURI(AUTHORITY, "update-thread/#", URI_UPDATE_THREAD); -- 更新 thread 根据 id
314
315 URI_MATCHER.addURI(AUTHORITY, "update-date", URI_UPDATE_THREAD_DATE);
316
317 URI_MATCHER.addURI(AUTHORITY, "update-top", URI_UPDATE_THREAD_TOP);
318
319 URI_MATCHER.addURI(
320 AUTHORITY, "conversations/favourite", URI_FAVOURITE_MESSAGES);
321
322 // Use this pattern to query the canonical address by given ID.
323 URI_MATCHER.addURI(AUTHORITY, "canonical-address/#", URI_CANONICAL_ADDRESS);
324
325 // Use this pattern to query all canonical addresses.
326 URI_MATCHER.addURI(AUTHORITY, "canonical-addresses", URI_CANONICAL_ADDRESSES);
327
328 URI_MATCHER.addURI(AUTHORITY, "search", URI_SEARCH);
329 URI_MATCHER.addURI(AUTHORITY, "searchSuggest", URI_SEARCH_SUGGEST);
330
331 // In this pattern, two query parameters may be supplied:
332 // "protocol" and "message." For example:
333 // content://mms-sms/pending?
334 // -> Return all pending messages;
335 // content://mms-sms/pending?protocol=sms
336 // -> Only return pending SMs;
337 // content://mms-sms/pending?protocol=mms&message=1
338 // -> Return the the pending MM which ID equals '1'.
339 //
340 URI_MATCHER.addURI(AUTHORITY, "pending", URI_PENDING_MSG);
341
342 // Use this pattern to get a list of undelivered messages.
343 URI_MATCHER.addURI(AUTHORITY, "undelivered", URI_UNDELIVERED_MSG);
344
345 // Use this pattern to see what delivery status reports (for
346 // both MMS and SMS) have not been delivered to the user.
347 URI_MATCHER.addURI(AUTHORITY, "notifications", URI_NOTIFICATIONS);
348
349 URI_MATCHER.addURI(AUTHORITY, "draft", URI_DRAFT);
350
351 URI_MATCHER.addURI(AUTHORITY, "locked", URI_FIRST_LOCKED_MESSAGE_ALL);
352
353 URI_MATCHER.addURI(AUTHORITY, "locked/#", URI_FIRST_LOCKED_MESSAGE_BY_THREAD_ID);
354
355 URI_MATCHER.addURI(AUTHORITY, "messageIdToThread", URI_MESSAGE_ID_TO_THREAD);
356 //+ req 153968, query the locked messages and draft messages, add by sunhengzhi.wt, 2016-03-30
357 URI_MATCHER.addURI(AUTHORITY, "message/locked", URI_MESSAGE_LOCKED);
358 URI_MATCHER.addURI(AUTHORITY, "message/draft", URI_MESSAGE_DRAFT);
359 //- req 153968, query the locked messages and draft messages, add by sunhengzhi.wt, 2016-03-30
360
361 // bug 154682, group send function, add by sunhengzhi.wt, 2016-04-22
362 URI_MATCHER.addURI(
363 AUTHORITY, "conversations/#/mult", URI_CONVERSATIONS_MULT_MESSAGES);
364
365 // bug154806, sunhengzhi.wt, 2016-04-30, add, get the database's size
366 URI_MATCHER.addURI(AUTHORITY, "mmssmssize", URI_MMSSMS_SIZE);
367
368 // bug168427, sunhengzhi.wt, 2016-05-25, add, add for the quick search box
369 URI_MATCHER.addURI(AUTHORITY, "search-address-word", URI_SEARCH_ADDRESS);
370 initializeColumnSets();
371 }
@Override
1658 public int update(Uri uri, ContentValues values,
....
....
1718 case URI_UPDATE_THREAD: ---- 然后从代码就看出来了,就是这里根据id更新
1719 long threadId;
1720 try {
1721 threadId = Long.parseLong(uri.getLastPathSegment());
1722 } catch (NumberFormatException e) {
1723 Log.e(LOG_TAG, "Thread ID must be a long.");
1724 break;
1725 }
1726 updateConversationUnread(db, threadId);
1727 MmsSmsDatabaseHelper.updateThread(db, threadId);
1728 break;
1729
1730 case URI_UPDATE_THREAD_DATE:
1731 MmsSmsDatabaseHelper.updateThreadsDate(db, selection, selectionArgs);
1732 break;
1733 case URI_UPDATE_THREAD_TOP:
1734 //bug 255905,modify,add,2017-05-09,start
1735 //if (mUseRcsColumns) {
1736 db.update("threads", values, selection, selectionArgs);
1737 //} else {
1738 // throw new IllegalStateException("Only Rcs has this URI:" + uri);
1739 //}
1740 //bug 255905,modify,add,2017-05-09,end
1741 break;
1742 default:
1743 throw new UnsupportedOperationException(
1744 NO_DELETES_INSERTS_OR_UPDATES + uri);
1745 }
然后其实是有2种方式更新的,
1. 强制更新 thread表
static void updateConversationDate(Context context) {
//Work around: com/android/providers/telephony/SmsProvider.java
Uri uri = ContentUris.withAppendedId(Telephony.Sms.Conversations.CONTENT_URI, -1);
int ret = context.getContentResolver().delete(uri, null, null);
}
2. 遍历 thread表,再根据 thread _id 更新
Cursor cursor = null ;
Cursor cursorSms = null ;
try {
Uri sAllThreadsUri = Threads.CONTENT_URI.buildUpon().appendQueryParameter("simple", "true").build();
String[] ALL_THREADS_PROJECTION = {
Threads._ID, Threads.DATE, Threads.MESSAGE_COUNT, Threads.RECIPIENT_IDS,
Threads.SNIPPET, Threads.SNIPPET_CHARSET, Threads.READ, Threads.ERROR,
Threads.HAS_ATTACHMENT,Threads.TYPE
};
cursor = mContext.getContentResolver().query( sAllThreadsUri, ALL_THREADS_PROJECTION , null ,null, "date DESC" );
Log.d(TAG, "===cursor=="+ cursor.getCount());
while(cursor!= null && cursor.moveToNext()){
int id = cursor.getInt(cursor.getColumnIndex(Threads._ID));
Log.d(TAG, "===id==="+ id);
/**
final String smsSelection = " thread_id = " + id ;
String[] aa = { Sms.BODY, Sms.DATE, Sms.TYPE,Sms.READ };
cursorSms = mContext.getContentResolver().query(BACKUPSMS_URI, aa, smsSelection, null, Mms.DATE + " DESC");
if(cursorSms != null && cursorSms.moveToFirst() ){
String spin = cursorSms.getString(0);
long date = cursorSms.getLong(1);
int type = cursorSms.getInt(2);
int read = cursorSms.getInt(3);
Log.d(TAG, "==spin:"+ spin + ",date:"+ date);
ContentValues cc = new ContentValues();
cc.put(Threads.DATE, date);
cc.put(Threads.SNIPPET_CHARSET, spin);
//cc.put(Threads.TYPE, type);
//cc.put(Threads.READ, read);
}
**/
//Telephony.Sms.Conversations
Uri uri = ContentUris.withAppendedId(Uri.parse("content://mms-sms/update-thread"), id);
//mContext.getContentResolver().update(Threads.CONTENT_URI, cc, "_id = "+ id, null);
mContext.getContentResolver().update(uri, cc, null, null);
}
} catch (Exception e) {
Log.d(TAG, "update======="+ e.toString());
}finally{
cursor! = null
...
...
}