Android ContactsContract: Last Modified Time - android

I would like to clone Android Contacts Phone into my own SQLite db. In order to save time, the cloning should be triggered when the single contact is newly created or being updated in the Android system. Thus, I want to have "last modified time" of each contact.
For API level 18 or above, it seems that i would get the last modified time of a single person contact by using ContactsContract.Contacts.CONTACT_LAST_UPDATED_TIMESTAMP. However for API Level 17 or below, it seems that there are some discussions before which suggested the use of "ContactsContract.RawContacts.VERSION" or "CONTACT_STATUS_TIMESTAMP".
For "CONTACT_STATUS_TIMESTAMP", it always returns ZERO or null. For "ContactsContract.RawContacts.VERSION", the version remained the same when i updated the photo, phone number or email of a person's contact.
Glad if someone would point out the mistakes i have made...
Reference:
How to get the last modification date for Contacts list (Add/Delete/Modify)

You can get notified when something changes using a ContentObserver. You will then need to retrieve the correct contact yourself. Of course that means having to have your app open when the contact changes or (more reasonably) running a background service.
In your service, create a content observer:
myObserver = new ContentObserver(new Handler()) {
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
if (!selfChange) {
//Note: when this (older) callback is used you need to loop through
//and find the contact yourself (by using the dirty field)
}
}
#Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
if (!selfChange) {
//Note: if you receive a uri, it has contact id
long rawContactId = ContentUris.parseId(uri);
//Note: be careful which thread you are on here (dependent on handler)
}
}
};
//NOTE: Then you need to remember to register and unregister the observer.
//getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, myObserver);
//getContentResolver().unregisterContentObserver(myObserver);
Your suggestion to use dirty is not a good solution alone, as this only temporarily indicates that the aggregate contact (owner) should be updated because something in the RawContact changed. This means if the contact gets synced before your app gets opened, dirty is already false (0) again.
Also note that the documentation for the column mentions that it was added in API 18, so as you are aware, it is only below 18 that you need a workaround. so the first step is to make sure you are using the column when you can
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
//continue with existing code
} else {
//use workaround (start service, or at least register observer)
}

Related

RealmObject changeListener

I'm trying to understand notification types in Realm from the Notifications section in the official docs, and when I'm using RealmObject addChangeListener in multiple managed object all of them are called when only one object is changing.
This is my code
Person first = realm.where(Person.class).equalTo("id", 0).findFirst();
first.addChangeListener(new RealmChangeListener<Person>() {
#Override
public void onChange(Person person) {
Log.e(LOG_TAG, "First element is changing: " + person);
}
});
Person second = realm.where(Person.class).equalTo("id", 1).findFirst();
second.addChangeListener(new RealmChangeListener<Person>() {
#Override
public void onChange(Person person) {
Log.e(LOG_TAG, "Second person is changing: " + person);
}
});
When I trigger an update in any of these Person objects (for example in first) both of the listeners are being called.
This what official docs say:
Listeners can also be attached to RealmObject instances as well as RealmResults instances. This allows you to react to changes to your objects and query results.
And
Lastly, typed-based change listeners will get notified when their referenced types change.
From what I understand the seen behaviour agrees with the second definition but I need to use the first behaviour, that's, I want to be notified when the object corresponding to that listener is changed.
So, if first Person is updated, only its corresponding listener get notified, not all Person listeners.
Right now it is happening because our change detection is not granular enough. It will trigger change listeners for all objects of the same type, not just those that changed.
Getting the changelisteners to only notify if the exact object has changed is being tracked here https://github.com/realm/realm-java/issues/989.
Use findFirstAsync() which returns a realmModel being empty and invalid. This is how you are able to get updates with its addChangeListener()
Specific change listener is now supported.
official release!
Demo

Get trigger from ContentObserver

Is there a way to tell why a ContentObserver was triggered? For example, if I am monitoring SMS via the "content://sms" URI and an SMS is sent or received, is there a way to deduce, within the ContentObserver class, what the SMS type is (I know I can set N ContentObservers, specifying different URI's, but I am hoping there is a way to tell from the ContentObserver class)?
BONUS: There is also a fun subtlety:
The 2nd method is only available from API level 16 onwards, so the code should not rely on a URI to work properly.
ContentObserver:
ContentResolver contentResolver = getBaseContext().getContentResolver();
contentResolver.registerContentObserver(Uri.parse("content://sms"), true,
new MessageObserver(new Handler(), getBaseContext()));
ContentObserver Class:
class SMSObserver extends ContentObserver {
public MyObserver(Handler handler) {
super(handler);
}
#Override
public void onChange(boolean selfChange) {
this.onChange(selfChange, null);
// What SMS type caused this to trigger????????
}
#Override
public void onChange(boolean selfChange, Uri uri) {
// What SMS type caused this to trigger????????
}
}
See you will receive Onchange in below mentioned cases
If any syncadapter is active upon that database then it will trigger onchange each time it pefrom sync, in this case you might receive onchange even if nothing is actually changed.
If there is actaul change in dataset.
Now coming to figuring out data which was changed, setting a observer for each possible URI is not at all good idea, with this you can although detect update or delete scenarios but sensing new insert will be a problem. I will suggest you following
Keep a single observer, upon initialization you can process entire data which is avilable initially, keep remebering column_id,update_timestamp and total row count once you progress forward, when onchange come next time with Coulmn_Id,update_timestamp and count you can figure out kind of change that was occured
--> Look for any rows having column_id greater then what you remeber, if it return any rows then certainly some new rows are inserted you can query them specifically
--> if above criteria fails then you need to look for update_timespamp any thing greater then last you remeber will tell if about rows that were updated
--> If both of above cirteria fial then look for difference in count which might tell you about delete operation.
if none of above occurs, clearly it was nothing then just ignore onchange signal. Hope it helps.

Android SyncAdapter Callback

I have implemented a SyncAdapter, AccountManager and private ContentProvider along the lines of the SimpleSyncAdapter sample project in the SDK. It is all working well.
Now I want to show a message to the user when new rows have been downloaded from the remote server that have a specific flag set. I need a callback from the SyncAdapter when a Sync has finished so I can do the query and display the message from an activity. I have seen a few questions on StackOverflow discussing this but none with a good answer.
How does one listen for progress from Android SyncAdapter? says that the SyncStatusObserver is useless. User mobibob suggests using a ResultReceiver to respond back to the UI from the sync thread.
How to know when sync is finished? suggests using an Intent in your SyncService.
How to signal sync-complete to the Android SyncManager? suggests using the SyncResult. The example code linked to by maxpower47 uses the SyncResult class to report exceptions but not to actually report if a sync was successfully completed.
I just don't know which is the best option and I have not seen any example projects where any of these solutions are used.
I know this is an old question, but I was asking the same thing myself.
What I found out as a good solution, specially because I'm dealing with local data as you are, is to use the following method from ContentResolver:
registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer)
This register an observer class that get callback when data identified by a given content URI changes. But that can only happens if your ContentProvider send the notification. So for example, if you want to get notified on the ContentObserver above for all updates done on your database through a ContentProvider, your ContentProvider should implement update similar to this:
#Override
public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {
// code goes here
this.getContext().getContentResolver().notifyChange(uri, null);
return 0;
}
Using notifyForDescendents when you do a registerContentObserver can be very useful.
This is an old question but I did some research in the past days and there are not many exemples on syncAdapter handling network requests and notifying the UI.
First you should use Loaders with contentProvider to make your life easier. You don't need to register for content resolver anymore the Loader does it for you. So it means your UI gets notified for anything that goes into your content provider.
What if nothing changed ? everything was up to date or you had a network error.
You can listen to the status of your syncAdapter as the Google I/O
app does, search for mSyncStatusObserver in the BaseActivity
I had a look at the default android email app and they use a Singleton with callBacks.
You can BroadcastIntents or use an eventBus (square Otto for exemple) to notify your UI of any behaviour.
I like the last one better because it gives you more granularity on the events that happen in the syncAdapter.
We ran into a similar situation and wrote a static Listener interface to the SyncAdapter. The listener is the activity and performs necessary actions when the data is available (update UI). This also works when the sync-adapter is called by the system during autosync where this listener would be null and the sync process would mind its own business.
class SyncAdapter extends AbstractThreadedSyncAdapter {
protected static Listener uiListener = null;
public interface Listener {
public void onSync();
}
public static void setListener(Listener l) {
uiListener = l;
}
public static void clearListener() {
uiListener = null;
}
protected void broadcastSync() {
if (uiListener != null)
uiListener.onSync();
}
public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
// call broadcastSync();
}
Then in the Activity, implement SyncAdapter.Listener interface.

ContentObserver is called even when there are no changes in the cursor

I have a content observer that should be notified when one of the contacts added by my sync adapter is modified.
I register and unregister the observer doing this:
private static final Uri MYAPP_CONTENT_URI = ContactsContract.RawContacts.CONTENT_URI.buildUpon().appendQueryParameter(RawContacts.ACCOUNT_NAME, SyncAdapter.MYAPP_ACCOUNT_NAME).appendQueryParameter(RawContacts.ACCOUNT_TYPE, MY_APP_ACCOUNT_TYPE).build();
public static void registerContentObserver() {
ContentResolver resolver = MyApplication.getAppContext().getContentResolver();
cursorContacts = resolver.query(MYAPP_CONTENT_URI, null, RawContacts.DELETED + "=0", null, null);
cursorContacts.registerContentObserver(MYAPP_URI_OBSERVER);
}
public static void unregisterContentObserver() {
if (cursorContacts != null) {
cursorContacts.unregisterContentObserver(MYAPP_URI_OBSERVER);
cursorContacts.close();
}
}
The problem is that even when the cursor is empty (getCount returns 0) after I register the observer I get a call to onChange what ever I do in the native address book.
Shoudn't the observer be called only when one of the entries in the cursor was modified?
The documentation states:
Register an observer that is called when changes happen to the content backing this cursor
What's "the content that is backing this cursor"? I thought it was the list of lookupuri of the contacts in the cursor but it looks like it is enough to have a change in the ContactsContract.RawContacts.CONTENT_URI.
I have also tried to register one observer for each Uri. It does not help. Although the documentation for ContentResolver.registerContentObserver states:
Register an observer class that gets callbacks when data identified by a given content URI changes.
Parameters
uri The URI to watch for changes. This can be a specific row URI, or a base URI for a whole class of content.
notifyForDescendents If true changes to URIs beginning with uri will also cause notifications to be sent. If false only changes to the exact URI specified by uri will cause notifications to be sent. If true, than any URI values at or below the specified URI will also trigger a match.
(I set notifyForDescendents to false but it shouldn't have called the observers in any case).
What's wrong?
Thank-you
It is up to the content provider to decide when to report changes. For complicated content providers (like the contacts provider) it can be very difficult to determine all of the specific URIs that change due to an operation, so they just report a global change when something happens.
Query parameters in your Uri, the Fragment, nor even the Scheme are considered when Observer Uri matching occurs. The only thing that matters is the Uri Authority and the Path Segments. Strict left to right matching occurs. I have not tested "*" in a path segment to denote a wildcard, but I suspect that it will not work.
Your particular Observer is ContactsContract.RawContacts.CONTENT_URI, so any time any contact content changes for any reason, your Observer will fire.

Difference between ContentObserver and DatasetObserver?

What is difference between ContentObserver and DatasetObserver?
When one or another should be used?
I get Cursor with single row. I want to be notified about data changes - eg. when row is updated.
Which observer class should I register?
If you are using a ContentProvider (via ContentResolver or Activity.managedQuery()) to get your data, simply attach a ContentObserver to your Cursor. The code in onChange() will be called whenever the ContentResolver broadcasts a notification for the Uri associated with your cursor.
Cursor myCursor = managedQuery(myUri, projection, where, whereArgs, sortBy);
myCursor.registerContentObserver(new ContentObserver() {
#Override
public void onChange(boolean selfChange) {
// This cursor's Uri has been notified of a change
// Call cursor.requery() or run managedQuery() again
}
#Override
public boolean deliverSelfNotifications() {
return true;
}
}
Make sure your ContentProvider is a "good citizen" and registers the Uri with the cursor after a query:
cursor.setNotificationUri(getContentResolver(), uri);
It should also notify the ContentResolver of any changes to the underlying data (for instance, during insert, delete, and update operations on your SQLite database):
getContentResolver().notifyChange(uri, null);
This approach is a good example of the Observer Pattern of object-oriented design.
I'm not sure if this question is still on anyone's radar. I have been struggling with the same question for a little while now. What I came up with as my litmus test for deciding whether to use a DataSet Observer or a ContentObserver is pretty straight-forward:
If I need to send a URI in my notification I use a ContentObserver. If I simply need to notify one object that another object has changed -- I use a DataSetObserver.
The delimiting factor, for me at least, is does the object that is sending out the notification expose it's underlying resources (be they objects, records, queries, or cursors) as "Universal Resource Identifiers" to the rest of the application; or does the object hide the source of its data.
To provide the supplement to ptc's answer, DataSetObserver is used for handling content changes in the Adapter, for example, it can be used for updating listview dynamically with Adapter. You can register a DataSetObserver using the Adapter#registerDataSetObserver() method.
DataSetObserver can also be used to observe the content changes in the Cursor in a similar fashion.
From my last app developed I can say.
The main difference between ContentObserver and DataSetObserver, is that ContentObserver makes to Observer any change affects on ContentProvider. On the other hand, DataSetObserver Observer any change effect on the database.

Categories

Resources