Telephony.Sms.Inbox.PERSON uses outdated Contacts.People._ID

Bounty Award . The prize will be awarded to the response that it receives from the filled Telephony.Sms.Inbox.PERSON value to the associated Contact using only the ContractsContact tables.


I read SMS messages in the standard way in my application:

  final String[] projection = {Telephony.Sms.Inbox.BODY, Telephony.Sms.Inbox.ADDRESS, Telephony.Sms.Inbox.READ, Telephony.Sms.Inbox.DATE, Telephony.Sms.Inbox.PERSON}; final Cursor cursor = ctx.getContentResolver().query(Telephony.Sms.Inbox.CONTENT_URI, projection, null, null, Telephony.Sms.Inbox.DEFAULT_SORT_ORDER); 

When filling out, the identifier returned from the Telephony.Sms.Inbox.PERSON index refers to the id of the outdated Contacts.People._ID and can be used to request additional contact information as follows:

  final String[] projection = {Contacts.People.DISPLAY_NAME}; final String[] selectionArgs = {contactId}; final Cursor cursor = ctx.getContentResolver().query(Contacts.People.CONTENT_URI, projection, Contacts.People._ID + " = ?", selectionArgs, null); 

Why will the relatively new telephony API use legacy tables instead of ContactsContract ?

Documentation Telephony.Sms.Inbox.PERSON :

Type: INTEGER (link to an element in the content: // contacts / people)

I tried unsuccessfully (but not unsurprisingly?) To find the matching with the identifier in any of the ContactsContract id fields, so I had to use the outdated APIs to resolve the requests that I needed, execute quickly.

Such requests include searching for messages with a specific contact, for which I only have a name. A contact may have several numbers, which may not be in the correct format, to potentially match the entries of Telephony.Sms.Inbox.ADDRESS .....

A workaround for using Telephony.Sms.Inbox.ADDRESS and ContactsContract.PhoneLookup is not the end of the world when moving from number to contact, but I still feel like I have to skip something here ?

Here is the process I use to get posts for "Joe Bloggs".

1) Request the ContactsContract table to confirm the contact by the name of Joe Bloggs on the device, or get a close match if the contact is really listed as "Joe Blogs ".

2) Using the verified name, I query the legacy Contact.People table to get all the associated identifiers for the contact as follows:

  final String selection = Contacts.People.DISPLAY_NAME + " LIKE ?"; final String[] projection = {Contacts.People.DISPLAY_NAME, Contacts.People._ID}; final String[] selectionArgs = {contactName}; final Cursor cursor = ctx.getContentResolver().query(Contacts.People.CONTENT_URI, projection, selection, selectionArgs, null); 

3) Using a list of legacy contact IDs, I request a message table like this:

  final String[] referredArgs = new String[contactIdArray.size()]; for (int i = 0; i < contactIdArray.size(); i++) { referredArgs[i] = contactIdArray.get(i); } final String referredSelection = Telephony.Sms.Inbox.PERSON + " IN " + "(" + TextUtils.join(",", referredArgs) + ")"; final String[] projection = {Telephony.Sms.Inbox.BODY, Telephony.Sms.Inbox.ADDRESS, Telephony.Sms.Inbox.READ, Telephony.Sms.Inbox.DATE, Telephony.Sms.Inbox.PERSON}; final Cursor cursor = ctx.getContentResolver().query(Telephony.Sms.Inbox.CONTENT_URI, projection, referredSelection, null, Telephony.Sms.Inbox.DEFAULT_SORT_ORDER); 

I hope someone tells me that I am going home here and there is a more obvious solution using modern APIs. I do not consider repeating the entire message table using ContactsContract.PhoneLookup optimized solution.

Thanks in advance.

+6
source share
3 answers

I would not use the Telephony.Sms.Inbox.PERSON field and would definitely not request the deprecated People apis if I were you. People apis has been deprecated for so long that you cannot count on all the devices that are there to properly support it.

First of all, you need to understand that there is no one-to-one communication between sms and contacts. SMS can come from a contactless phone number, one contact, several contacts, a combination of contacts and non-contacts, alpha-numeric identifiers and even other, more rare options.

In the future, you should carefully read the stock code and how it processes the correctly named “recipient ID,” which you can get from the SMS collection, there is a collection called canonical-addresses (or canonical-address ), which serves as a mapping between the telephone number (or comma-separated list of telephones) and recipient ID. The code executes a single query at startup to cache the entire table in memory, and then uses it to match between phones and recipient identifiers.

Here is the mapping class

+4
source

Why is the relatively new Telephony API using legacy tables rather than ContactsContract?

What you mean is not new. In Telephony.java, you see that it relies on an existing provider content://sms :

  public static final class Inbox implements BaseColumns, TextBasedSmsColumns { /** * The {@code content://} style URL for this table. */ public static final Uri CONTENT_URI = Uri.parse("content://sms/inbox"); 

It was already there in Donut (and probably earlier, but I did not check).

What's new in Kitkat is the ability to change the SMS application .

+1
source

I do not understand your concern correctly, but I am working on a similar project, here is the basic code and the main important columns for extracting and displaying a message:

 ContentResolver contentResolver = getContentResolver(); final String[] projection = new String[]{"*"}; Cursor SMSL = contentResolver.query(Telephony.Sms.CONTENT_URI, projection, null, null, "date ASC"); int msgscount = SMSL.getCount(); if (msgscount>0) { msgs = new String[SMSL.getCount()][msgs_column_count]; int i = 0; while (SMSL.moveToNext()) { progress.setProgress(i); msgs[i][0] = SMSL.getString(SMSL.getColumnIndex("address")); msgs[i][1] = SMSL.getString(SMSL.getColumnIndex("date_sent")); msgs[i][2] = SMSL.getString(SMSL.getColumnIndex("date")); msgs[i][3] = SMSL.getString(SMSL.getColumnIndex("type")); msgs[i][4] = SMSL.getString(SMSL.getColumnIndex("body")); msgs[i][5] = SMSL.getString(SMSL.getColumnIndex("read")); if (SMSL.getString(SMSL.getColumnIndex("service_center")) != null){ msgs[i][6] = SMSL.getString(SMSL.getColumnIndex("service_center")); }else{ msgs[i][6] = ""; } i++; } SMSL.close(); }else{ msgs = new String[0][0]; Toast.makeText(getApplicationContext(),"No messages found!",Toast.LENGTH_LONG).show(); } 

If you need help with this or retrieving messages, let me know.

-one
source

Source: https://habr.com/ru/post/1013808/


All Articles