10

With ICS, we now have APIs for the Calendar! :)

My question is, how do we determine if an event has been updated. Ideally this could be done with a BroadcastReceiver, but I don't think there is one that is publicly accessible. There is some event broadcasted, but I don't think it's accessible to non-system apps.

02-06 23:05:05.316: I/CalendarProvider2(9201): Sending notification intent: Intent { act=android.intent.action.PROVIDER_CHANGED dat=content://com.android.calendar }
02-06 23:05:05.320: W/ContentResolver(9201): Failed to get type for: content://com.android.calendar (Unknown URL content://com.android.calendar)

This is my work around for now. Is there a better way? Users can get squimish if they see a service running for along time and often will kill it to save battery life.

public class CalendarUpdatedService extends Service {

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        int returnValue = super.onStartCommand(intent, flags, startId);

        getContentResolver().registerContentObserver(
                CalendarContract.Events.CONTENT_URI, true, observer);

        return returnValue;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    ContentObserver observer = new ContentObserver(new Handler()) {

        @Override
        public boolean deliverSelfNotifications() {
            return true;
        }

        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);

            //code goes here to update
        }
    };

}
AakashM
  • 62,551
  • 17
  • 151
  • 186
runor49
  • 3,870
  • 1
  • 21
  • 18

2 Answers2

7

I use a static singleton class (you could also extend Application) with methods to register/unregister multiple observers for different providers such as the calendar provider(s). I store this in a HashMap so I can determine which observers are registered at a later time.

It is ugly but there doesn't seem to be a better solution.

EDIT This receiver:

public class CalendarChangedReceiver extends BroadcastReceiver {
    private static final String TAG = "CalendarChangedReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "calendar changed! "+intent.toUri(Intent.URI_INTENT_SCHEME));
    }
}

With this manifest declaration:

<receiver android:name=".CalendarChangedReceiver">
    <intent-filter>
        <action android:name="android.intent.action.PROVIDER_CHANGED"/>
        <data android:scheme="content"/>
        <data android:host="com.android.calendar"/>
    </intent-filter>
</receiver>

Will catch changes to Events and Calendars in ICS. If you are using the old undocumented calendar provider the only solution is ContentObserver(s) in a static class or service.

roflharrison
  • 2,300
  • 23
  • 26
  • There isn't a broadcast at this point, so I have to use a ContentObserver, which means I have to have a service running all of the time to listen for it... – runor49 Apr 13 '12 at 20:55
  • 1
    That filter should catch the broadcast you mentioned in your question and appears to be one method the stock calendar app uses to update its widget (https://github.com/android/platform_packages_apps_calendar/blob/master/src/com/android/calendar/widget/CalendarAppWidgetService.java) see the CalendarFactory class. If you use a static singleton class (or extend Application) then you won't have to use a service. This isn't necessarily better, just an alternative that might help with users killing your service. – roflharrison Apr 13 '12 at 23:17
0
<intent-filter>
        <action android:name="android.intent.action.EVENT_REMINDER" />
        <data android:scheme="content"/>
        <data android:host="com.android.calendar"/>
    </intent-filter>

will capture the EVENT's notification (eg: 30 min before the event)

Dan Alboteanu
  • 9,404
  • 1
  • 52
  • 40