Accessing the internal calendar database inside Google Android applications

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)

  1. ContentResolver contentResolver = context.getContentResolver();
  2.  
  3. final Cursor cursor = contentResolver.query(Uri.parse("content://calendar/calendars"),
  4.         (new String[] { "_id", "displayName", "selected" }), null, null, null);
  5.  
  6. while (cursor.moveToNext()) {
  7.  
  8.     final String _id = cursor.getString(0);
  9.     final String displayName = cursor.getString(1);
  10.     final Boolean selected = !cursor.getString(2).equals("0");
  11.    
  12.     System.out.println("Id: " + _id + " Display Name: " + displayName + " Selected: " + selected);
  13. }

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.

  1. Uri.Builder builder = Uri.parse("content://calendar/instances/when").buildUpon();
  2. long now = new Date().getTime();
  3. ContentUris.appendId(builder, now - DateUtils.WEEK_IN_MILLIS);
  4. ContentUris.appendId(builder, now + DateUtils.WEEK_IN_MILLIS);
  5.  
  6. Cursor eventCursor = contentResolver.query(builder.build(),
  7.         new String[] { "title", "begin", "end", "allDay"}, "Calendars._id=" + id,
  8.         null, "startDay ASC, startMinute ASC");
  9.  
  10. while (eventCursor.moveToNext()) {
  11.     final String title = eventCursor.getString(0);
  12.     final Date begin = new Date(eventCursor.getLong(1));
  13.     final Date end = new Date(eventCursor.getLong(2));
  14.     final Boolean allDay = !eventCursor.getString(3).equals("0");
  15.    
  16.     System.out.println("Title: " + title + " Begin: " + begin + " End: " + end +
  17.             " All Day: " + allDay);
  18. }

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

  1. moamen’s avatar

    here is the solution, use the new content provider

    Content provider URI
    Old: content://calendar/
    New: content://com.android.calendar/

    good luck

  2. moamen’s avatar

    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

  3. John’s avatar

    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));

  4. Surya Gopal’s avatar

    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.

  5. moamen’s avatar

    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 SMS

    in case of email and SMS where the number of the SMS recipient can be saved?
    if any one know please help

  6. moamen’s avatar

    Surya Gopal, send me your email and i’ll send u a class to access DB

  7. cad13’s avatar

    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

  8. Domenok’s avatar

    can u give me more detailes please? Thanks

  9. cad13’s avatar

    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 !

  10. cad13’s avatar

    Solution : use “event_id=” instead of “_id=”

  11. David Cheney’s avatar

    Thank you thank you thank you …

  12. bender’s avatar

    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?

  13. Mark’s avatar

    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.

  14. PB’s avatar

    hey, ur post is very good.. m trying to parse xml data in my application from a site.. can u help me wid some code..

    Thanks

  15. Kapuddi’s avatar

    Hi, Jim.

    When I insert one new Calendar Event into Google calendar from my app,
    the fail log message was given:

    10-05 00:30:44.171: ERROR/DatabaseUtils(8479): Error inserting transparency=0 dtstart=1285891200000 title=TestCalendar _sync_dirty=1 dtend=1285891200000 visibility=0 allDay=1 lastDate=1285950628697 hasAlarm=0 eventStatus=1 into table Events
    10-05 00:30:44.171: ERROR/DatabaseUtils(8479): android.database.sqlite.SQLiteConstraintException: error code 19: constraint failed
    10-05 00:30:44.171: ERROR/DatabaseUtils(8479): at android.database.sqlite.SQLiteStatement.native_execute(Native Method)

    Can you give me some advice?

    Next is the sample code:
    ================================================================================
    ContentValues event = new ContentValues();

    //event.put(“title”, mAct.getString(R.string.read) + “: ” + title);
    event.put(Events.TITLE, “TestCalendar”);

    long startTime = startC.getTimeInMillis();
    long endTime = endC.getTimeInMillis();

    event.put(Events.DTSTART, startTime);
    event.put(Events.DTEND, endTime);
    event.put(Events.ALL_DAY, 1);
    event.put(Events.STATUS, Events.STATUS_CONFIRMED);
    event.put(Events.VISIBILITY, Events.VISIBILITY_DEFAULT);
    event.put(Events.TRANSPARENCY, Events.TRANSPARENCY_OPAQUE);
    event.put(Events.HAS_ALARM, 0);

    if (resetTag) {
    mAct.getContentResolver().update(Events.CONTENT_URI, event, Events._ID + “=” + contentId, null);
    return contentId;
    }else {
    Uri uri = mAct.getContentResolver().insert(Events.CONTENT_URI, event);
    return ContentUris.parseId(uri);
    }

  16. Rusty’s avatar

    Hi Jim, thanks for the post. I have found it very useful to get me going with the calendars.

    For any others – I’m using HTC Desire with Android 2.2 (Froyo) and this URI content://com.android.calendar

    Cheers,
    Rusty

  17. cow’s avatar

    Hi,

    Can anyone tell me how to get the last modification time of the event?

    Thanks

  18. David’s avatar

    Hi Jim,

    Thank you for posting your article.
    Can you give me a tip how to replace android.provider.Calendar in the Google source code? Where can I find the @hide files?

    Thank you.
    David

  19. Talha’s avatar

    Hi there,
    can anyone tell me if there is a way to query through code if there is a calendar available on the device. As far as I know there are two calendars, google and corporate??? or is it that we can only get this info through cursor???

    Secondly, I have noticed that if there is another application using the calendar, my app fails to connect to calendar…

    Like the code that Jim Blackler has written to connect to calendar:
    final Cursor cursor = contentResolver.query(Uri.parse(“content://calendar/calendars”),
    (new String[] { “_id”, “displayName”, “selected” }), null, null, null);

    Are there any known exceptions to this method or return values from which one could get to know what exactly failed the cursor from opening???

    thanx

  20. jimblackler’s avatar

    Hi Pierrot, Corporate (on Motorola devices) has a different provider, I believe there is a note in the article.

  21. Shimon Shnitzer’s avatar

    Hi,

    When using the code you gave here to launch the event ACTION_EDIT intent, can I somehow set the default calendar selected for the event ?

    What used to work in the past was I created an event in my code (using the .insert function, the launched the intent ACTION_EDIT with intent.setDate().

    This then displayed the event edit dialog with the calendar_id I used to create the event in code set.

    Now the dialog does open, but it selected the first calendar by default, so if I press the Done button – I get TWO events – one that I created in code with my desired calendar, and another one created by the EDIT dialog – in the first calendar.

    Am I making any sense here ?

    Any solution ?

    TIA

  22. Paresh’s avatar

    Hello, i have referred your article, really its AWESOME,

    but one think i want to know about the Calendar events, How do i fetch events for the particular date only ??

    please please let me know !!

  23. Awais’s avatar

    01-18 20:45:33.589: ERROR/ActivityThread(472): Failed to find provider info for calendar

    can anyone help. I guess my emulater don’t have any calendar installed yet. How to do it?
    Help Jim, Please drop mail.
    Will be grateful
    thanks

  24. Frankie’s avatar

    My Final Year Project is building with android apps and i want to add a calender function on it. it ‘s so useful for me but my emulator don’t have any calendar installed yet.

    Could u mind to help me to solve this problem?

    thank for so much !!!!!!

  25. Mike’s avatar

    I’m hearing from one user that my app is not working on gingerbread. Does anyone know if the content provider changed?

  26. Shekhar’s avatar

    I have my own calendar. I want to get my gmail events to my calendar.
    any help regarding this…
    thanks in advance

  27. vishwas’s avatar

    plz tell me the source code to connect messaging application of android emulator with a button on simple android application?????????

  28. sudarsan’s avatar

    Hi,
    From developer prospective…
    How can I get to know if a calendar event from android device is updated or deleted. I need to do some operations if there is any update on calendar events.

  29. John’s avatar

    http://pastebin.com/jpnqTp1n

    There is a pastebin of my current Calendar Access API. All you have to do is set the calendarID to an existing calendar and you should be good to go.

    If you use this please make note of it so the user can see. (eg. in About or something.) Thanks :)

  30. John’s avatar

    Sudarsan, I don’t think you can register any listeners or call backs on the content provider itself, but perhaps you can store the contents of the event within your application, and then check if they changed when you need to.

    That would allow you to check for edits, but if the event was deleted it shouldn’t contain the eventID that you have from when you created the event or from when you originally looked up the data.

    @Jim, you can delete my previous comment awaiting moderation. I have pastebinned my class rather than taking up half a page on your blog. Sorry about that.

  31. abhay’s avatar

    hi…I am new to android. I just copied the above and made a app but that app prints nothing… I want this to work badly…

    waiting for reply
    Thanks in advance

  32. lurecas’s avatar

    Thank you so much. It was so helpful for my project… what i can’t understand it’s why Google don’t put a tutorial on how to access the calendar…it seems that it’s some kind of secret…

    Thank you again!!

  33. Andreas’s avatar

    There is somethin strange happening. This code (ok, similar code) works fine on my HTC Desire with Android 2.2 and most other phones.

    But there are some users (Samsung with Android 2.2 and Magick with 2.2.1) reporting, that the code used in my app works fine on the mobile calendar, but the entered event is never synced to their Google calendar on the web. If they open the event using the stock calendar app and save it, it will be saved.

    I can’t figure out, what maybe has changed and what I am missing.

    Anybody any idea?

  34. Alex’s avatar

    I get reports that the Motorola XOOM does not work with this URI, does any one know if 3.0 has a different URI and how about 2.3, any one?

  35. Ellen’s avatar

    Thanks a lot! I used this information in the class I’m teaching.

  36. tushar’s avatar

    sir , please tel me how to accessing the notification about event added,deleted,updated from default calendar of android to our own application.

    please please let me known…..

  37. saurabh’s avatar

    i want to get specific calendar event type when any event of calendar changes by the user in device….so please help me…

  38. Bmjones’s avatar

    Alex,

    As far as 3.0 goes, I noticed one change. I was testing on a Motorola Xoom and found that the Calendar._id column is not in the DB. Just testing I removed that portion of the projection and everything else worked fine.

    I still have some more testing to do, but though that might help out.

  39. Bmjones’s avatar

    In 3.0 I noticed problems in trying to filter event results based on the calendar id using “Calendar._id=”.

    Changing the filter to “calendar_id=” seems to work just fine in 3.0. I double checked it in 2.3 and works there too.

    Hope this helps others.

  40. Murali’s avatar

    Thank you for the great explanation and example code. I am writing an android app that will automatically set the ringer to silent mode if a users calendar shows as busy. Do you mind if i use your example for reading the calendar ?

  41. jimblackler’s avatar

    Thanks Murali, I’d be delighted if you’d use my example. Best of luck with your app.

  42. Eric’s avatar

    I have successfully got it to add calendar events however, I am also accessing the ExtendedProperties URI adding name value pairs in it. When I do this, it causes random Google Services Framework force closes. After some searching on the internet it seems the error message is caused by a failure in google calendar sync. The events added don’t get synced to my gCal.

    Anyone tapping into the ExtendedProperties and get it to work successfully?

  43. chezi’s avatar

    Thank you for the great explanation and example code

  44. Matteo’s avatar

    @Bmjones:
    you said that you can run it on android 2.3. I can’t in my Samsung Galaxy S2 (That is 2.3.3).
    This is the code I use:

    Cursor cursor = getContentResolver().query(Uri.parse
    (“content://com.android.calendar/calendars”),
    new String[]{“calendar_id”,”displayname”},null,null,null);

    is it correct ??
    “content://com.android.calendar/calendars” is good for 2.3 ??
    thank you for help !!
    matteo

  45. Anil’s avatar

    Hi Jim,
    I have followed your tutorial to access the internal android calendar database. It works for all entries except for recurring events. The cursor does not return any recurring events at all. Can you please help me here. I am running this on Froyo (2.2) Following is my cursor declaration –

    String[] projection = new String[] { “title”, “description”, “dtstart”, “eventLocation” };
    String selection = “(calendar_id=” + calID + “)AND ” + (now – window)
    + “<dtstart AND dtstart< " + (now + (window));
    String sortorder = "dtstart ASC";

    Cursor managedCursor = getCalendarManagedCursor(projection, selection,
    "events", sortorder);

    private Cursor getCalendarManagedCursor(String[] projection,
    String selection, String path, String sort) {
    Uri calendars = Uri.parse("content://calendar/" + path);
    Cursor managedCursor = null;
    try {
    managedCursor = getContentResolver().query(calendars, projection,
    selection, null, sort);
    } catch (IllegalArgumentException e) {
    Log.w(DEBUG_TAG,
    "Failed to get provider at [" + calendars.toString() + "]");
    }

    if (managedCursor == null) {
    // try again
    calendars = Uri.parse("content://com.android.calendar/" + path);
    try {
    managedCursor = getContentResolver().query(calendars,
    projection, selection, null, sort);
    } catch (IllegalArgumentException e) {
    Log.w(DEBUG_TAG,
    "Failed to get provider at [" + calendars.toString()
    + "]");
    }

  46. Pete’s avatar

    Hello Jim,
    I was wondering whether you was also experiencing weird issues with Google Calendar:
    while using your example my “all day” events start at 01am and finish at 01am the next day.
    However the time of “startTime-endTime” events is correct.
    Have you experienced this behaviour?

  47. Ash’s avatar

    Thanks for above info. I have a doubt, in my app, i need to show only todays/current days’ events.How do i specify the range for that ?

    Also, if i need 2 show events for today & tomorrow, how can i do that ? Do i need to use a different URI :- “/instances/when” OR “/instances/whenbyday” ?
    Pl help

· 1 · 2 · 3 ·

Reply

Your email address will not be published. Required fields are marked *