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();
- final Cursor cursor = contentResolver.query(Uri.parse("content://calendar/calendars"),
- (new String[] { "_id", "displayName", "selected" }), null, null, null);
- while (cursor.moveToNext()) {
- final String _id = cursor.getString(0);
- final String displayName = cursor.getString(1);
- final Boolean selected = !cursor.getString(2).equals("0");
- System.out.println("Id: " + _id + " Display Name: " + displayName + " Selected: " + selected);
- }
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();
- long now = new Date().getTime();
- ContentUris.appendId(builder, now - DateUtils.WEEK_IN_MILLIS);
- ContentUris.appendId(builder, now + DateUtils.WEEK_IN_MILLIS);
- Cursor eventCursor = contentResolver.query(builder.build(),
- new String[] { "title", "begin", "end", "allDay"}, "Calendars._id=" + id,
- null, "startDay ASC, startMinute ASC");
- while (eventCursor.moveToNext()) {
- final String title = eventCursor.getString(0);
- final Date begin = new Date(eventCursor.getLong(1));
- final Date end = new Date(eventCursor.getLong(2));
- final Boolean allDay = !eventCursor.getString(3).equals("0");
- System.out.println("Title: " + title + " Begin: " + begin + " End: " + end +
- " 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
-
Is it possible to create/modify events in the built-in calendar?
-
How timely! Just what I have been looking for. Thanks for taking the time to document
-
Excellent! Thanks for the rundown, you’ve saved me a lot of pain…
-
Is there a way to run this example in the SDK’s emulator? For me it fails here:
final Cursor cursor = contentResolver.query(Uri.parse(“content://calendar/calendars”), …);
returning “null” everytime.
-
I know it’s asking a lot, but could you create a “quick add” event app.
I used a Palm Treo 650 before my Droid, and the day-view of the Palm’s calendar was used more than the phone portion.I constantly check, add, reschedule events on the calendar. And it has notification events (with defaults for alert tone/vibrate and time before event)
-
Hi Jim,
Thanks for the beautiful write-up and the code. I have a quick question. Is it possible to query the Calendar database with event’s creation time/date? If yes then could you please tell how.
Also, I am capturning the change notifications from calendar using the ContectObserver but my problem is how do I distinguish if it’s add event or delete event?
Thanks in advance for your help.
-Ram -
Hi Jim,
I want to write a calendar app which can read and write meetings.
Is there any possibility to get a calendar app like your ‘Quick Calendar’ run in the Android SDK to set some “example meetings”? When I install your app on my SDK i get every time the error: “The application Calendar Storage (process com.android.calendar) has stopped unexpectedly. Please try again.” Don’t know how to solve, so you’re my last chance! :-)Thank you in advance for your help!
Ray -
thanks Jim.
Another question please. How to update or delete the calendar entries? Could you please mention how the query looks like?
Thanks,
-Ram -
Hi Jim,
I don’t have any Android device to test my programs. I can only test them with the Android emulator, but emulator has a calendar app installed. I tried to install the calendar with the Calendar.apk from http://code.google.com/p/android/issues/detail?id=1389 and the CalendarProvider.apk but when i click on the icon the same error comes.
Currently I’m using Android 2.0 emulator. I alredy tried it with 1.5 and 1.6, but everytime with the same error!Greetings
Ray -
If you want to write events to a calendar you can follow this tutorial [->http://android.arnodenhond.com/tutorials/calendar%5D
-
Hi Jim,
I am new to android and I was trying to use Android’s Native Calendar.
Thanks for an excellent write-up.I had couple of questions regarding the usage of the native calendar.
I am trying to build an application which can interact with the calendar to add/edit/delete events from the native calendar.
In your blog you are talking about reading the events from the calendar. Is it possible to perform the CRUD operations on the native calendar using ContentProviders alone ?
Thanks in advance,
Varun -
Dear Jim,
I am trying to get this to work with android sdk 2.0.1. I had put the Example class from your project into my standard android project & it didn’t work. I noticed that there wasn’t a Calendar class in the Android.jar file in eclipse.
Is it possible that I need to recompile the android 2.0.1 sdk and include the calendar class?
Should I be using a different android sdk?
Thank you for time,
Sean
-
Actually, I think I meant which version of the android OS you used because the phone I am running has android 2.0.1 on it. There’s no way to debug this inside of the emulator so I’ll have to reflash my phone if necessary.)
Is there a way to find the sqlite file itself perhaps?
Please excuse me for asking so many questions. I thank you very much for your time in this.
-
thank you! this was very helpful.
-
Hi Jim,
Fantastic blog. Can you give me an advice on what I need to extract events from calendar instead of the calendar as a whole. Am planning to build an application which pulls events from the phone calendar then send it as sms messages to contacts.
Many thnx
-
I can’t get this working. I’ve downloaded the source code and compiled and run on my g1 to no avail. I’ve downloaded your quickcalendar app and that works fine… any ideas,
-
Well it works but it just shows a blank screen with the app title. I have also set up multiple appointments for the week to test…
Any ideas, this would really help.
I have a G1 running stock android 1.6
thanks
-
Perfect, don’t believe i didn’t read the code properly. thanks. For some reason my console isn’t outputting anything so i sightly modified and used a textview to output. Now all i have to work out is why i can’t write to the calendar even though permissions are added (any ideas on that one will be much appreciated :) )
Thanks again
-
Hi Jim, great blog post. I’d been looking for something like this for a while. Would you happen to know if it’s possible to do this with Gmail’s content provider as well to read e-mail? I made a first attempt but couldn’t get it to work but maybe you’ve had better luck?
-
Thanks, I’ll give that a try. There’s a new app called Slide Screen that just came out that’s displaying both calendar info as well as Gmail so I imagine they must be using a similar method to what you described here. I’ll let you know if I’m able to make progress. If anyone’s got this working (Gmail) please let us know!
-
Thanks Jim :)
What about corporate calendar? is that just using a different Uri for the query?
I’d like to make a small app that registers my visits to customers…
I did that on windows mobile but I cannot find out how to do it on android :( -
Jim – can you share anything the Intents you use to add calendar events ? I couldn’t see those in your example.
I’ve tried adding events from code, following
http://android.arnodenhond.com/tutorials/calendar
and
http://www.developer.com/ws/article.php/3850276/Working-with-the-Android-Calendar.htmWhile I did manage to add events, I also broke my Google Calendar in a way which means that it won’t sync to the cloud any more. Also, I can no longer edit my calendar via the Web interface. Apparently it is waiting for a human at Google to review it!
That made me a little nervous about adding events directly to the database, so I am hoping to find a safer way…
-
Jim – thanks – that’s perfect. And (I hope) it will be harder to break the calendar database with that approach.
Did you ever stray into creating repeating events, by the way ?
-
Jim – thanks for the clear blog..
You say it’s possible to build a android.jar with the calendar.
This would be very helpfull for me to build a app.But i keep solving errors when i remove the @hide in the calendarprovider.
And i can’t seem to find much on that item on the web.Can you sent me in the good direction with this..or do you maybe have a android.jar with the calendar class?
Thanks.
-
Thanks for posting this, it really was helpful when I started integrating my project with the android calendar. I found a few other helpful sources as well, and have compiled a “wrapper” class to wrap the calendar in a more usable way.
-
First, I REALLY appreciate your tutorial. It made all the difference in the world on my latest app.
Something I’ve found worth mention.. Your tutorial, as it stands, worked great on my Motorola Cliq, but I was getting bug reports from all over, so after a lot of tracking, I figured out that it’s a good practice to also look for the value “name” in addition to “displayName”. “displayName” seems to be optional, so I have my code look for both and go with whatever it finds.
ContentResolver contentResolver = this.getContentResolver();
final Cursor cursor = contentResolver.query(Uri.parse(“content://calendar/calendars”),
(new String[] { “_id”, “displayName”, “name”, “selected” }), null, null, null);String myDisplayName=”NONE”;
String myCalName=”NONE”;while (cursor.moveToNext()) {
final String _id = cursor.getString(0);
final String displayName = cursor.getString(1);
final String calName = cursor.getString(2);
final Boolean selected = !cursor.getString(3).equals(“0”);
if (displayName.contains(“gmail.com”)) { useCalId=_id; myDisplayName=displayName; myCalName=calName; }
if (calName.contains(“gmail.com”)) { useCalId=_id; myDisplayName=displayName; myCalName=calName; }
if (selected) { useCalId=_id; myDisplayName=displayName; myCalName=calName; }
if (Debug) { Log.i(“DEBUG”, “totalCals: “+String.valueOf(totalCals)+” CalId: “+String.valueOf(_id)+” Calendar: “+displayName+” CalName: “+calName+” selected: “+String.valueOf(selected)); }
}And once again, thank you VERY much for getting me off in the right direction!
– Craig
SweetMerch.com -
Jim, echoing everyone here once more; THANKS for the hard work you put into this tutorial.
I’m having some trouble getting your code to run on my Motorola CLIQ (v1.5). I checked out your AndroidReadCalendarExample from your SVN, “tethered” my CLIQ and launched your code. I am getting the following errors from the console though:
[2010-03-05 00:34:51 – AndroidReadCalendarExample]Starting activity net.jimblackler.readcalendar.MainActivity on device
[2010-03-05 00:34:52 – AndroidReadCalendarExample]ActivityManager: Can’t dispatch DDM chunk 46454154: no handler defined
[2010-03-05 00:34:52 – AndroidReadCalendarExample]ActivityManager: Can’t dispatch DDM chunk 4d505251: no handler defined
[2010-03-05 00:34:53 – AndroidReadCalendarExample]ActivityManager: Starting: Intent { comp={net.jimblackler.readcalendar/net.jimblackler.readcalendar.MainActivity} }These are the last four lines from the console, so somehow it is not reading the calendar correctly.
Thanks in advance,
Aleksey -
John – great helper class, thank you. Although, I was wondering if you could either parse it down a little or provide the rest of the code for it…not having all of the imports makes it a little challenging. Also, what build of the SDK did you use for this?
Thanks
-Kyle -
One other question for John…what is the CalendarListItem class around line 185? Is that something in the SDK or within your project?
– kyle
-
Hi Jim,
Many thanks for this forum and it has been extremely useful to me. Thank you.
This would be very useful to me now – Can you provide detailed description on creating a new calendar (and not events) on a device and getting it sync-ed with the google cloud ? What has been your experience with Google api on this front as well ?
many thanks once again,
rajeev -
Jim,
Great article. I really appreciate you providing this Calendar example and blog. Has your employer OKed the release of the source code for QuickCalendar yet? It would be really helpful to see the source code of a full application.
Thanks,
Michael -
Great article. Been wanting an app to turn off my phone ringer when in certain meetings, now I can write one.
-
My HTC Eris did an update today to 2.1 – I didn’t have a backup of my calendar but I see that my calendar storage has 13.5 MB so I assume my data is still there – is there a way for me to access this?
-
meant to add that I can’t access my calendar…
-
Hey Kyle, I’ve worked with that piece of code quite a bit since I originally posted on here.
CalendarEventItem was just a small class to hold the name of a calendar and it’s id.
That is the entire class, and I cannot at this time post any more of the project.
However, I can post a few examples of how it is used if you want although it’s pretty self explanatory.
1 Thing I cannot figure out though is how to get a reminder to be used. I just can’t get it to use a reminder =[
-
hello Jim, please provide us with help for froyo calendar
i’m working in my app for my nexus one to add events to calendar but from now i don’t know how to move forwardthanks for your help and wish we receive more
-
i can provide you with the calendar 2.2 from my phone in case it will help
106 comments
Comments feed for this article
Trackback link: http://jimblackler.net/blog/wp-trackback.php?p=151