The Android phone operating system provides close integration with three excellent services from Google; email, address book and calendar. In addition it has a thriving third party app scene with a great variety of free and commercial applications on the Market. In theory this should mean that apps can provide new services to the user based on the Google service data they have already synced on the phone.
However in the case of calendar data this has proven a bit tricky. Google provide an API to access calendar data via the internet, and this can be used directly from Android apps. Unfortunately this also requires a working data connection, time and battery life to get at the data. In addition it will need the app to prompt for the user's credentials (user name and password).
All this seems unnecessary when the data you want is right there on the phone already. Since there is an API that any application can use to access the user's contact (address book) data directly on the phone without going to the internet. It's called android.provider.Contacts and is documented here. So why doesn't android.provider.Calender exist?
The answer
The answer is that is does exist – although it is not documented, and it is not included with the standard Google Android SDK. It is a little-known fact that it is possible to download the Android source, force the provider classes to be included by removing the @hide annotation that protects it, and make your own version of the SDK. This can be compiled against apps from which calendar queries can then be made.
This is how I originally built my app Quick Calendar – a 'lite' read only version alternative to the built-in calendar application released early 2009. This uses the same data used by the built-in calendar application, already synced onto users' Android phones. Judging by my inbox it's been the most popular hobby application I've ever put out. I've since had a number of inquires from other developers as to how I managed get at the internal calendar data on Android.
Firstly I would say that getting at the data by a custom-build SDK is possible but awkward. For one thing it is a pain keeping up to date with the latest changes and staying in sync with the Android Eclipse plug in.
The good news is you don't actually need to use the calendar provider SDK classes to get at the data. Android exposes data across applications by using a feed system similar to web-based feeds, and query syntax similar to SQL. As a result, provided your app has the correct user permission (android.permission.READ_CALENDAR) you can query the database from the names, and continue to use standard SDKs such as 1.5 or 1.6. In the absence of specific SDK support for calendars, it's only slightly less convenient to directly use the provider's internal URIs (e.g. "content://calendar/calendars") directly.
Warning
At this point I should point out that there's a reason why Google haven't officially exposed the internal calendar APIs. This is probably because they anticipate future changes to the calendar format. Once they've published an SDK the formats are to some extent set in stone and they'd like to avoid that. In my experience the formats have been stable since I first discovered the feed. However, don't be surprised if future firmware changes break any apps that use the feed. In this event you'll have to update your app and re-upload it to the Market. It's not that big a worry, certainly not enough to avoid using this great feature - the ability to present users' calendar data in new ways to them.
Example
I've uploaded an example project to http://svn.jimblackler.net/jimblackler/trunk/workspace/AndroidReadCalendarExample. All the calendar reading code is in http://svn.jimblackler.net/jimblackler/trunk/workspace/AndroidReadCalendarExample/src/net/jimblackler/readcalendar/Example.java.
To read the calendar data in your own app firstly add android.permission.READ_CALENDAR under <manifest> in your application's AndroidManifest.xml.
Please note that you will probably have to use a real phone to test your app in development, because the emulator included with the SDK does not include the Google services (there will simply be no calendar database present to query).
Then get an android.content.ContentResolver and make a query to content://calendar/calendars to enumerate all the available calendars
on the phone. The '_id' column will give you the calendar's ID (referenced in events). You can get rough documentation of all the columns supported by looking at core/java/android/provider/Calendar.java. (As mentioned previously, this file is part of the public open source Android project but is not part of the official Android SDK from Google)
-
ContentResolver contentResolver = context.getContentResolver();
-
-
-
while (cursor.moveToNext()) {
-
-
-
}
Once you have a calendar ID you can use your ContentResolver object to obtain the events from that calendar. Note how a 'where' clause of 'Calendars._id=??' is employed to fetch only events of that particular calendar. This clause could query whichever columns your app required, using an SQL-like syntax. Note also how the Uri.Builder was used to build up a URL including date bounds for the query.
-
Uri.Builder builder = Uri.parse("content://calendar/instances/when").buildUpon();
-
ContentUris.appendId(builder, now - DateUtils.WEEK_IN_MILLIS);
-
ContentUris.appendId(builder, now + DateUtils.WEEK_IN_MILLIS);
-
-
null, "startDay ASC, startMinute ASC");
-
-
while (eventCursor.moveToNext()) {
-
-
" All Day: " + allDay);
-
}
Note that all dates in the calendar format are stored as UTC (the number of milliseconds that have elapsed between midnight 1st January 1970 and the event in Greenwich UK).
This is the basics of calendar access on Android. I haven't covered all the columns (these can be seen in the SDK source linked above) and I haven't covered modification. Notheless I hope this information allows other developers to build great calendar-aware apps for Android. Please do leave queries in the comments here, and if you use this information to make an app please do tell us about it in the comments here.
Update
To access the Corporate Calendar on Motorola devices, use "content://calendarEx" in place of "content://calendar".
Update 2
For Android devices using 2.2 (Froyo) or greater, where previously you had content://calendar you should write content://com.android.calendar
-
here is the solution, use the new content provider
Content provider URI
Old: content://calendar/
New: content://com.android.calendar/good luck
-
now i can write event to the froyo calendar, my problem is adding reminder to it
i can add reminder to it by using the content://com.android.calendar/reminders but i don’t know why it’s not working and on the first sync the reminder got removed.
i tried to use calendarAlerts but didn’t work
please help -
static String contentProvider;
static Uri remindersUri;
static Uri eventsUri;
static Uri calendars;if(Build.VERSION.RELEASE.contains(”2.2″))
contentProvider = “com.android.calendar”;
else
contentProvider = “calendar”;remindersUri = Uri.parse(String.format(”content://%s/reminders”,contentProvider));
eventsUri = Uri.parse(String.format(”content://%s/events”,contentProvider));
calendars = Uri.parse(String.format(”content://%s/calendars”,contentProvider)); -
HI,
I have gone through your blog about android examples. its very nice, and more understandable format.
I am new to android, iam working rit now on android, plz help me how to connect to sqlite and access the data, and update, plz help me with small example. -
can any one help me to understand this.
the reminder table has a column called method, its allowed values are 0,1,2,3
0 for default and do nothing
1 add reminder
2 email reminder
3 SMSin case of email and SMS where the number of the SMS recipient can be saved?
if any one know please help -
Surya Gopal, send me your email and i’ll send u a class to access DB
-
Hi Jim,
Thanks for this tuto.
Do you know how to proceed for deleting events between 2 dates ?
I tried to use the second part of your code (which display all events between 2 dates), but how to delete them instead of displaying them ?
I also tried using
Uri url = getContentResolver().delete(eventsUri, event)
but how to parse the events from date to date ?Thank you if you can help…
Christian
-
Ok I can parse my events using your example, but unfortunately, I cannot delete any of them !
Do you have an idea for that ?
I tried :
Uri eventsUri = Uri.parse(uriCal + “/events”);
Uri uri = ContentUris.withAppendedId(eventsUri, eventid);
int nb = contentResolver.delete(uri, null , null);
or this :
Uri eventsUri = Uri.parse(uriCal + “/events”);
int nb = contentResolver.delete(eventsUri, “_id=”+id, null);But nothing happens, my events are still there !
-
Solution : use “event_id=” instead of “_id=”
-
Thank you thank you thank you …
-
Thanks for this great article! :)
There is something that confuses me about this and another tutorial which I found here: http://www.developer.com/ws/article.php/3850276/Working-with-the-Android-Calendar.htm
In this tutorial you get the start and end times of an event in the query via “begin” and “end”.
In the other tutorial is explained how to submit a new event to the calendar, and the start and endtimes there are put with:
event.put(”dtstart”, startTime);
event.put(”dtend”, endTime);I tried to insert a new event and replaced “dtstart” with “begin” and “dtend” with “end” but received an exception that I need to put a value for “dtstart”.
So my question is, why do you use “begin” to get the time when retrieving an event and “dtstart” when inserting a new one? Aren’t these the column names of the calendars db?
-
Has anybody been able to figure out what the calendar provider URI is for HTC SenseUI phones such as the Hero, Incredible and Desire? The code on this site crashes with an unknown URI error when I try to run it on any of those phones.
‹ Previous · 1 · 2

62 comments
Comments feed for this article
Trackback link: http://jimblackler.net/blog/wp-trackback.php?p=151