Detecting Changes in Android Contacts

Introduction

In this post, we'll explore how to detect changes in Android contacts. Android OS provides a mechanism for contact storage known as the Contacts Provider. This provider offers a structured set of data and a standard interface that connects data across different processes.

Structure of Android Contacts

ContactsRaw Table

  • _id: RAW_CONTACT_ID
  • account_name: e.g., email address
  • account_type: e.g., com.google.com
  • deleted: Indicates if the contact is deleted

The ContactsContract.RawContacts.CONTENT_URI table contains original contacts, mainly storing RAW_CONTACT_ID. Contact details are stored in the ContactsContract.Data table.

Contacts Table

  • _id: CONTACT_ID (refers to a group of RAW_CONTACT_IDs)
  • lookup: Provides a link to all contact details in this table

The Contacts.CONTENT_URI table groups RawContacts based on merging rules. If a raw contact can't be grouped with an existing contact, a new contact is created. The LOOKUP_KEY is a permanent link to a contact, remaining consistent even if CONTACT_ID changes due to merging.

ContactContract Table

  • _id: CONTACT_DETAIL_ID
  • lookup: Permanent link to contact
  • raw_contact_id: Refers to RAW_CONTACT_ID in the ContactsRaw table
  • contact_id: Refers to CONTACT_ID in the Contacts table
  • version: Reflects updates to contact records
  • data1 to data16: Data content (e.g., email, phone number, address)
  • mime_type: Type of record (e.g., email, number, address)
  • is_primary: Indicates if there are multiple instances of contact information (e.g., primary phone number)

The ContactsContract.Data.CONTENT_URI table contains contact details. Each contact may have multiple records here (e.g., one for name, one for phone number, one for email). contact_id is a reference to the Contacts table, and raw_contact_id references the original contact.

AggregationException Table

  • RAW_CONTACT_ID1: First raw contact ID
  • RAW_CONTACT_ID2: Second raw contact ID
  • AggregationExceptions.TYPE: Type of exception (e.g., automatic merging, keeping separate, keeping together)

The AggregationException table specifies pairs of raw contacts that should not be grouped. The type can be:

  • TYPE_AUTOMATIC: Automatic merging by the content provider
  • TYPE_KEEP_SEPARATE: Contacts remain separate
  • TYPE_KEEP_TOGETHER: Contacts are merged until explicitly separated by the user

Automatic Merging Rules

Contacts are merged automatically based on:

  • Matching name and surname
  • Matching name and surname in different orders
  • Matching surname and a short first name
  • Matching name or surname with one phone/email
  • One contact lacking a name/surname but sharing a phone/email

Detecting Changes

Using ContentObserver

To detect contact changes, you can use ContentObserver, which provides two methods:

  • onChange(boolean selfChange): Triggers when something changes
  • onChange(boolean selfChange, Uri uri): Provides the URI of the changed contact (available since API 16)

Version Number

Each contact record includes a version number. By maintaining a local database of stored versions, you can compare version numbers to detect changes.

Timestamp

You can track the last change using a timestamp (available since API 18). By querying with this timestamp, you can identify which contacts have been modified.

Detecting New Contacts

To detect new contacts, save the last RAW_CONTACT_ID and query for contacts with higher IDs. When a significant change occurs, a new RAW_CONTACT_ID is generated. Check

for changes in the LOOKUP_KEY to ensure you’re capturing all updates accurately.

Detecting Removed Contacts

To determine if a contact has been removed, query the database for the contact using the LOOKUP_KEY. This process might be resource-intensive as it involves checking each contact of interest.

SyncAdapter and Server Synchronization

The Contacts Provider is designed to handle synchronization between a device and an online service. A SyncAdapter can be used to manage contact synchronization with your custom account and server. This component handles tasks such as checking network availability, scheduling, and restarting synchronization, which can be useful for applications involving contact management.

Issues Encountered

During synchronization, I encountered an issue where updating a contact (replacing its content) led to the contact being removed and a new one being created with a different RAW_CONTACT_ID. According to the documentation, this happens if the raw contact changes significantly. Despite attempts to reproduce this issue through both simple queries and batch operations, I couldn't replicate it consistently.

What Would Be Great?

A feature that would significantly enhance contact management would be a listener that notifies which contacts (including third-party accounts) are new, deleted, or changed. Additionally, a history feature that allows querying changes since a specific timestamp would be very beneficial.

Helpful Links

This article was written to help me remember the details of working with Android contacts. If you find any inaccuracies or have additional insights, please leave a comment below.

Comments

Popular posts from this blog

Skate Tricks Recognition Using Gyroscope

Play table

Counting dice and train wagons using computer vision