ContentObserver should call if and only if ContactsContract.Contacts.CONTENT_URI changes
Asked Answered
B

3

11

As my application uses content from android.provider.ContactsContract.Data (API > 11) and ContactsContract.Contacts.CONTENT_URI (API < 11) to populate Contacts.

I've tried to registerContentObserver() against these provider. But it calls my ContentObserver even if I tries to Call a person from device as soon as I put the call. It does trigger my ContentObserver which is not useful for me as there's no Content Change in Contacts Provider.

Root Cause:

Seems like LAST_TIME_CONTACTED or something in ContactsContract.Contacts.CONTENT_URI do changes when a call has been made from device which legitimate wokes up by ContentObserver.

Tried:

private class ContactsContentObserver extends ContentObserver {
    public ContactsContentObserver() {
        super(null);
    }

    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        Zname.getPreferences().setRefreshContact(true);
    }
}

Registered ContentObserver in OnCreate() of Activity

ContactsContentObserver contactsContentObserver = new ContactsContentObserver();
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, false, contactsContentObserver);

Tried with notifyForDescendents as false on registerContentObserver. Still it triggers out ContentObserver

Ques:

How can one register ContentObserver which triggers if and only if contacts information is under CRUD(Create,Update,Delete) except Last_Time_Contacted or its descendants?

Bikales answered 21/5, 2014 at 12:35 Comment(0)
B
0

As android.provider.ContactsContract content provider has it's own complexity which makes ContentObserver tough to notify only on contacts content change except it's LAST_TIME_CONTACTED field as every fellow come across say these and so it is.

One need to develop it's own logic whether contacts data get updated or not when ContentObserver notifies.

Points to consider building logic whether contacts really get updated or not.

  • Checking on these basis of Last Time checked. Depends on the requirement.
  • Adding ContentObserver in Service which is STICKY so it can be there when contacts get change.

Sync Phone Book Logic :- As I've maintained contacts using SQLite, so checking up whether that exist or not and w.r.t building logic.

ContentValues values;
Cursor cursor = Zname.getApplication().getContentResolver().query(DBConstant.All_Contacts_Columns.CONTENT_URI,null,DBConstant.All_Contacts_Columns.COLUMN_CONTACT_NUMBER+ "=?",new String[] { _contact.getContactNumber() },null);

 if (cursor.getCount() <= 0) {
        cursor.moveToFirst();
        Zname.getApplication().getContentResolver().delete(DBConstant.All_Contacts_Columns.CONTENT_URI,DBConstant.All_Contacts_Columns.COLUMN_CONTACT_NUMBER+ "?=",new String[] { _contact.getContactNumber() });
        Log.i(TAG, "Updating zname phonebook");
        values = new ContentValues();
        values.put(DBConstant.All_Contacts_Columns.COLUMN_CONTACT_ID,_contact.getContactId());
        values.put(DBConstant.All_Contacts_Columns.COLUMN_CONTACT_NUMBER,_contact.getContactNumber());
        values.put(DBConstant.All_Contacts_Columns.COLUMN_DISPLAY_NAME,_contact.getContactName());
        values.put(DBConstant.All_Contacts_Columns.COLUMN_ZNAME_DP_URL_SMALL,_contact.getContactPhotoUri().toString());

        Zname.getApplication().getContentResolver().insert(DBConstant.All_Contacts_Columns.CONTENT_URI,values);

        if (cursor != null)
              cursor.close();
   }
Bikales answered 1/7, 2014 at 12:32 Comment(0)
L
5

The fundamental problem here is that registering for ContactsContract.Contacts.CONTENT_URI isn't working as you might reasonably think.

The reason why you get updates even if notifyForDescendents is false is because the Uri triggering the update is... ContactsContract.Contacts.CONTENT_URI and not the contact row that is being dialled.

The offending code in the Contacts app can be found at GrepCode and there is a bug filed for this on Google Code.

So to answer your question, you can't register a ContentObserver which will trigger for specific fields on a contact. You would need to have something in your app which will keep track of calculating the differences whenever onChange fires.

Lacewing answered 25/6, 2014 at 13:20 Comment(2)
Someone wrote there that "From Android 4.3 we have time stamp for each contacts that will be updated whenever we make any change in the particular contacts" . Any idea what he's talking about, and more importantly, how to use it to filter out callbacks that don't help as nothing has changed? Maybe he's talking about this: developer.android.com/reference/kotlin/android/provider/… ?Gona
Looking on somewhere else, it's also not reliable at all: https://mcmap.net/q/1158976/-what-exactly-contact_last_updated_timestamp-flag-returnsGona
B
0

As android.provider.ContactsContract content provider has it's own complexity which makes ContentObserver tough to notify only on contacts content change except it's LAST_TIME_CONTACTED field as every fellow come across say these and so it is.

One need to develop it's own logic whether contacts data get updated or not when ContentObserver notifies.

Points to consider building logic whether contacts really get updated or not.

  • Checking on these basis of Last Time checked. Depends on the requirement.
  • Adding ContentObserver in Service which is STICKY so it can be there when contacts get change.

Sync Phone Book Logic :- As I've maintained contacts using SQLite, so checking up whether that exist or not and w.r.t building logic.

ContentValues values;
Cursor cursor = Zname.getApplication().getContentResolver().query(DBConstant.All_Contacts_Columns.CONTENT_URI,null,DBConstant.All_Contacts_Columns.COLUMN_CONTACT_NUMBER+ "=?",new String[] { _contact.getContactNumber() },null);

 if (cursor.getCount() <= 0) {
        cursor.moveToFirst();
        Zname.getApplication().getContentResolver().delete(DBConstant.All_Contacts_Columns.CONTENT_URI,DBConstant.All_Contacts_Columns.COLUMN_CONTACT_NUMBER+ "?=",new String[] { _contact.getContactNumber() });
        Log.i(TAG, "Updating zname phonebook");
        values = new ContentValues();
        values.put(DBConstant.All_Contacts_Columns.COLUMN_CONTACT_ID,_contact.getContactId());
        values.put(DBConstant.All_Contacts_Columns.COLUMN_CONTACT_NUMBER,_contact.getContactNumber());
        values.put(DBConstant.All_Contacts_Columns.COLUMN_DISPLAY_NAME,_contact.getContactName());
        values.put(DBConstant.All_Contacts_Columns.COLUMN_ZNAME_DP_URL_SMALL,_contact.getContactPhotoUri().toString());

        Zname.getApplication().getContentResolver().insert(DBConstant.All_Contacts_Columns.CONTENT_URI,values);

        if (cursor != null)
              cursor.close();
   }
Bikales answered 1/7, 2014 at 12:32 Comment(0)
G
0

About LAST_TIME_CONTACTED as you mentioned, it's deprecated and will always return 0 from API 29, so you shouldn't use it...

https://developer.android.com/reference/android/provider/ContactsContract.ContactOptionsColumns#LAST_TIME_CONTACTED

If you want to monitor entire address-book or even one contact, indeed you use:

applicationContext.contentResolver.registerContentObserver(ContactsContract.Contacts.CONTENT_URI, false, observer)

And then you query the whole address book:

applicationContext.contentResolver.query(ContactsContract.Contacts.CONTENT_URI, projection,
        null, null, null
)?.use { cursor ->
    while (cursor.moveToNext()) {
        Log.d("AppLog", "" + DatabaseUtils.dumpCurrentRowToString(cursor))
    }
}

You can change it to be focused on specific contact you want to monitor.

You can use the CONTACT_LAST_UPDATED_TIMESTAMP of each contact to see if anything changed on it. Then you can also save to yourself all the things you wish to exclude and include in the checks. That's very customizable by your own needs.

You might want to use some debouncing technique, especially if you monitor the entire address book. Here's how to do it:

Kotlin Android debounce

Gona answered 30/4 at 8:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.