It is hard to find documentation about this, so I am collecting here all the information I found. If you are in a hurry or just do not like to read, go to How to get data from the SMS section .
content: // MMS-SMS / conversations
This is the URI of the Mms and SMS provider ... which allows us to simultaneously query the MMS and SMS databases, and mix them in one stream (called chains).
Why is it important? Well, this is the standard way to receive MMS and SMS messages; for example, when you receive an SMS message and click on the notification panel, it sends the broadcast intent as follows: content://mms-sms/conversations/XXX , where XXX is the identifier of the conversation.
Get a list of all conversations
The only thing you need to do is request content://mms-sms/conversations Uri:
ContentResolver contentResolver = getContentResolver(); final String[] projection = new String[]{"*"}; Uri uri = Uri.parse("content://mms-sms/conversations/"); Cursor query = contentResolver.query(uri, projection, null, null, null);
Note: usually when you call query and want to return all columns, you can pass null as a parameter to projection . However, you cannot do this with this provider, so I use * .
Now you can scroll through the Cursor as usual. These are the most important columns you would like to use:
_id is the message identifier. Is the captain explicit for salvation? Not really. This identifier can be used to get detailed information using either content://sms or content://mms .date no explanation required.thread_id - conversation idbody The content of the last SMS in this conversation. If it is MMS, even if it has a text part, it will be null .
Note: if you request content://mms-sms/conversations , it will return a list of different conversations, whose _id is the last SMS or MMS in each conversation. If you request content://mms-sms/conversations/XXX , it will return each SMS and / or MMS to the conversation whose identifier is XXX .
How to distinguish between SMS and MMS
Usually you need to know what type of message you are processing. The documentation reads:
The virtual column, MmsSms.TYPE_DISCRIMINATOR_COLUMN , can be queried in the projection for the query. Its value is either "mms" or "sms", depending on whether the message presented next is an MMS message or an SMS message, respectively.
I think this refers to this variable ... however, I could not get it to work. If you tell me how to change this or edit this post.
So far this is what I have done and it seems to work, but there should be better ways:
ContentResolver contentResolver = getContentResolver(); final String[] projection = new String[]{"_id", "ct_t"}; Uri uri = Uri.parse("content://mms-sms/conversations/"); Cursor query = contentResolver.query(uri, projection, null, null, null); if (query.moveToFirst()) { do { String string = query.getString(query.getColumnIndex("ct_t")); if ("application/vnd.wap.multipart.related".equals(string)) {
How to get data from SMS
So, you have an SMS identifier, then you only need:
String selection = "_id = "+id; Uri uri = Uri.parse("content://sms"); Cursor cursor = contentResolver.query(uri, null, selection, null, null); String phone = cursor.getString(cursor.getColumnIndex("address")); int type = cursor.getInt(cursor.getColumnIndex("type"));
How to get data from MMS data?
MMS are a little different. They can be built with various parts (text, audio, images, etc.); therefore, it will show how to retrieve each kind of data separately.
So let's assume that I have an MMS identifier in the mmsId variable. We can get detailed information about this MMS using the provider content://mms/ :
Uri uri = Uri.parse("content://mms/"); String selection = "_id = " + mmsId; Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
However, only an interesting read column, which is 1 if the message has already been read.
How to get text content from MMS
Here we should use content://mms/part ... for example:
String selectionPart = "mid=" + mmsId; Uri uri = Uri.parse("content://mms/part"); Cursor cursor = getContentResolver().query(uri, null, selectionPart, null, null); if (cursor.moveToFirst()) { do { String partId = cursor.getString(cursor.getColumnIndex("_id")); String type = cursor.getString(cursor.getColumnIndex("ct")); if ("text/plain".equals(type)) { String data = cursor.getString(cursor.getColumnIndex("_data")); String body; if (data != null) {
It may contain different parts of the text ... but usually it will be only one. Therefore, if you want to delete a loop, it will work most of the time. Here's what the getMmsText method looks like:
private String getMmsText(String id) { Uri partURI = Uri.parse("content://mms/part/" + id); InputStream is = null; StringBuilder sb = new StringBuilder(); try { is = getContentResolver().openInputStream(partURI); if (is != null) { InputStreamReader isr = new InputStreamReader(is, "UTF-8"); BufferedReader reader = new BufferedReader(isr); String temp = reader.readLine(); while (temp != null) { sb.append(temp); temp = reader.readLine(); } } } catch (IOException e) {} finally { if (is != null) { try { is.close(); } catch (IOException e) {} } } return sb.toString(); }
How to get an image from MMS
This is the same as getting the text part ... The only difference is that you will look for another type of mime:
String selectionPart = "mid=" + mmsId; Uri uri = Uri.parse("content://mms/part"); Cursor cPart = getContentResolver().query(uri, null, selectionPart, null, null); if (cPart.moveToFirst()) { do { String partId = cPart.getString(cPart.getColumnIndex("_id")); String type = cPart.getString(cPart.getColumnIndex("ct")); if ("image/jpeg".equals(type) || "image/bmp".equals(type) || "image/gif".equals(type) || "image/jpg".equals(type) || "image/png".equals(type)) { Bitmap bitmap = getMmsImage(partId); } } while (cPart.moveToNext()); }
Here's what the getMmsImage method looks like:
private Bitmap getMmsImage(String _id) { Uri partURI = Uri.parse("content://mms/part/" + _id); InputStream is = null; Bitmap bitmap = null; try { is = getContentResolver().openInputStream(partURI); bitmap = BitmapFactory.decodeStream(is); } catch (IOException e) {} finally { if (is != null) { try { is.close(); } catch (IOException e) {} } } return bitmap; }
How to get the sender address
You will need to use the content://mms/xxx/addr provider content://mms/xxx/addr , where XXX is the MMS identifier:
private String getAddressNumber(int id) { String selectionAdd = new String("msg_id=" + id); String uriStr = MessageFormat.format("content://mms/{0}/addr", id); Uri uriAddress = Uri.parse(uriStr); Cursor cAdd = getContentResolver().query(uriAddress, null, selectionAdd, null, null); String name = null; if (cAdd.moveToFirst()) { do { String number = cAdd.getString(cAdd.getColumnIndex("address")); if (number != null) { try { Long.parseLong(number.replace("-", "")); name = number; } catch (NumberFormatException nfe) { if (name == null) { name = number; } } } } while (cAdd.moveToNext()); } if (cAdd != null) { cAdd.close(); } return name; }
Final thoughts
- I can’t understand why Google, with thousands of millions of dollars, is not paying a student or anyone else to document this API. You must check the source code to find out how it works, and, even worse, they will not publicize the constants used in the database columns, so we must write them manually.
- For other types of data inside MMS, you can apply the same thought as above ... it's just a matter of knowledge like mime.