Search code examples
androidtelephonyandroid-sms

How to retrieve only the last message of every conversation including the locked message using Telephony.Sms?


I'm using the below code to retrieve a message from sms.

private List<String> getEveryLastMessages(){
    List<String> listSms = new ArrayList<String>();
    ContentResolver contentResolver = getActivity().getContentResolver();

    Cursor c = contentResolver.query(Telephony.Sms.Inbox.CONTENT_URI, // Official CONTENT_URI from docs
                new String[] { Telephony.Sms.Inbox.BODY }, // Select body text
                null,
                null,
                Telephony.Sms.Inbox.DEFAULT_SORT_ORDER); // Default sort order

    int totalSMS = c.getCount();

    if (c.moveToFirst()) {
        for (int i = 0; i < totalSMS; i++) {
            listSms.add(c.getString(0));
            listSms.add("\n");
            c.moveToNext();
        }
    } else {
        //Do something, no messages
    }
    c.close(); 

        return listSms;
}

my problem is all of the message was retrieved and except the locked message.

what I'm trying to achieve is retrieve only the last message of every conversation including the lock messages and populate it into my recyclerview adapater to show it as inbox.


Solution

  • If you want the last message in each conversation, regardless of whether it's sent or received, there's a handy built-in URI that you can use, in lieu of just grabbing everything and filtering it yourself.

    Telephony.Sms.Conversations.CONTENT_URI (in the android.provider package) can be used in a ContentResolver query to retrieve a summary of the available conversations. For example:

    Cursor c = contentResolver.query(Telephony.Sms.Conversations.CONTENT_URI,
                                     null, null, null, null);
    

    This query will return with three columns:

    • Telephony.Sms.Conversations.SNIPPET ("snippet")
    • Telephony.Sms.Conversations.MSG_COUNT ("msg_count")
    • Telephony.Sms.Conversations.THREAD_ID ("thread_id")

    The SNIPPET column will be the most recent available message in that conversation.

    Unfortunately, starting with Marshmallow (API level 21), any app that is not the default messaging app has access to only a restricted view of the SMS table. Such an app can only get messages with a Telephony.Sms.TYPE of MESSAGE_TYPE_INBOX or MESSAGE_TYPE_SENT. This means that you won't get MESSAGE_TYPE_FAILED, MESSAGE_TYPE_DRAFT, etc., unless your app is the current default app.

    However, the Telephony.Sms.LOCKED column is a completely separate categorization from the TYPE column, and so should not figure into the restricted view. That is, you should be able to get locked messages, as long as they're sent or inbox, no matter if your app is the default or not. Of course, it's possible that a manufacturer has altered any of this described behavior, and you might need to account for that in your app.