Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding architecture of Android contacts

I am developing an Android app which needs to know when a contact is added/updated/deleted.

So I read several posts for it. I understand that we can get notified through Content observers whenever a contacts gets changed, but we can't get which contacts have been added/updated/deleted. So I have read the official APIs and prepared my design how to capture that particular contact.

So what I thought at the start

  1. We will store all the contact IDs, deleted flag and version
  2. Whenever contacts get changed I will get my table's row count and row count from Android's system.
  3. If my rowcount is less than systems row count then a contact has been deleted.
  4. If my rowcount is greater than systems row count then a contact has been added.
  5. And if these are not the cases then one of the contacts version has been changed.

I have also learned that Android doesn't delete the contact if it is deleted by user, but it sets 0 on deleted flag. So in these cases the row count will be same.

Android also changes the row ID of a contact many times as stated in the official docs. So how can we uniquely identify them like lookup uri and if not then we have to put observer for that also.

So I want to know whether the above is correct? And in the case a contact is added will it be added to the last row of cursor or not means if I check the last row of system database for contacts will it give me the contact added or not.

like image 284
Nikhil Agrawal Avatar asked Apr 04 '13 13:04

Nikhil Agrawal


2 Answers

Let me explain as much as I could. Basically your policy looks pretty good, but actually it is bit more complex than you thought.

On Android, a contact can be associated with several raw contacts, which may be provided from many data providers, such as Google, Facebook, Skype and so on. For example, if one of your friends in your local contacts is also using Skype, there are two raw contacts existing separately in ContactContracts.RawContacts, but they will be aggregated automatically and show up just as one contact when you query to ContactsContract.Contacts.

That is also why it's hard to identify a contact uniquely, because you can split or join them anytime you want. LOOKUP_KEY isn't very handy for this case.

Many apps except Google only provide a one-way sync, i.e. only from service to contacts, so they are read-only. In this case, the deleted flag will not be used and simply deleted during their synchronization process. Thus, you can not simply rely on the flag.

Though there isn't a good simple solution, I guess it's much easier to achieve what you want, if you observe for a specific RawContacts, not Contacts. Hope this helps your understanding.

like image 50
tnj Avatar answered Sep 29 '22 11:09

tnj


I think the best practice is to monitoring whenever a contact has aggregate to another one and identify them by the contactName, not the _ID or CONTACT_ID. Take a look at this possibly contacts operations:

Insert

A Contact cannot be created explicitly. When a raw contact is inserted, the provider will first try to find a Contact representing the same person. If one is found, the raw contact's CONTACT_ID column gets the _ID of the aggregate Contact. If no match is found, the provider automatically inserts a new Contact and puts its _ID into the CONTACT_ID column of the newly inserted raw contact.

Update

Only certain columns of Contact are modifiable: TIMES_CONTACTED, LAST_TIME_CONTACTED, STARRED, CUSTOM_RINGTONE, SEND_TO_VOICEMAIL. Changing any of these columns on the Contact also changes them on all constituent raw contacts.

Delete

Be careful with deleting Contacts! Deleting an aggregate contact deletes all constituent raw contacts. The corresponding sync adapters will notice the deletions of their respective raw contacts and remove them from their back end storage.

Query

If you need to read an individual contact, consider using CONTENT_LOOKUP_URI instead of CONTENT_URI. If you need to look up a contact by the phone number, use PhoneLookup.CONTENT_FILTER_URI, which is optimized for this purpose. If you need to look up a contact by partial name, e.g. to produce filter-as-you-type suggestions, use the CONTENT_FILTER_URI URI. If you need to look up a contact by some data element like email address, nickname, etc, use a query against the ContactsContract.Data table. The result will contain contact ID, name etc.


The problem, though, is that you could have two 'Phillip Morris' in your contact list that aren't the same person.

For further information, see this section of Android Classes Documentation.

like image 23
A. Cristian Nogueira Avatar answered Sep 29 '22 11:09

A. Cristian Nogueira