8

I have followed the tutorial in this link - http://jimblackler.net/blog/?p=151&cpage=2#comment-52767 to access the internal android calendar database (even though it is not officially supported by the SDK). It works for all entries except for recurring events. The cursor does not return any recurring events at all. Can someone help me here. 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()
                            + "]");
        }`
AnilV
  • 179
  • 2
  • 12

2 Answers2

16

Use the Instances table if you need to locate recurring events.

The URIs for querying it are:

  • instances/when/*/* - All instances between two times (milliseconds)
  • instances/whenbyday/*/* - All instances between two times (days)
  • instances/groupbyday/*/* - Same as whenbyday, but grouped by the start day

The list of columns in that table are:

  • _id - The ID of this instance
  • event_id - The event it was created from
  • begin - Begin time (milliseconds)
  • end - End time (milliseconds)
  • startDay - Start day of instance
  • endDay - End day of instance
  • startMinute - Minutes since midnight (0..1440)
  • endMinute - Minutes since midnight

You can also use the columns from the Events and Calendar tables.

You can see an example on the same page that you linked: http://jimblackler.net/blog/?p=151

Example:

String[] projection = new String[] {
        "title", "description", "begin", "eventLocation"
};
String selection = "calendar_id = " + calID;
String path = "instances/when/" + (now - window) + "/" + (now + window);
String sortOrder = "begin DESC";
Cursor managedCursor = getCalendarManagedCursor(
        projection, selection, path, sortorder);

Edit: It seems Google got around to document the Calendar Provider. Browse to Calendar Providier | Google Developers for more information.

Markus Jarderot
  • 86,735
  • 21
  • 136
  • 138
  • Thanks a lot MizardX for your answer. Just wondering though, how do I get the title of the meetings using this "Instances" table. Do I have to use the event_id and then search the "Events" table for the meeting title information? – AnilV Aug 23 '11 at 05:25
  • @user887304 I added an example – Markus Jarderot Aug 23 '11 at 05:47
  • Hi MizardX, you are a "LIFE SAVER". I just tried out your example and it works like a charm. Thanks so much for your answer. – AnilV Aug 23 '11 at 06:27
  • 1
    Hi MizardX, In your example above can you tell me how to modify the query if I want to retrieve all the events without filtering for "calendar_id". Can I just set the "Selection" variable to null? – AnilV Aug 28 '11 at 04:07
  • You could, but you would also get instances for calendars that are currently hidden. To only get instances for selected calendars, use `String selection = "selected = 1"` – Markus Jarderot Aug 28 '11 at 09:24
  • Is there a uri for querying attendees data? – Guy May 07 '12 at 08:27
  • @DragonWork The calendar API was available before, but not official. There was no documentation, so you'd have to go digging in the source-code to find out how to use it. – Markus Jarderot Jun 30 '12 at 22:24
  • I knew that the calendar API was available before. My question was: Is your code above (the instances table) working under SDK 14? – DragonWork Jun 30 '12 at 22:42
  • 1
    @DragonWork It should for the most part. There might have been some minor changes to URI's or column names. Double-check with the documentation. – Markus Jarderot Jun 30 '12 at 23:05
  • @MarkusJarderot some of the problem getting event in before sdk 14. –  Nov 05 '12 at 06:48
  • @harshid Are you asking if this is available before sdk 14? Yes. This has been available since Android 1.0. The URI's might have changed slightly in the meantime though. – Markus Jarderot Nov 05 '12 at 07:37
  • where have you found the URIs, can you post the corresponding URL – Erdinc Ay Dec 17 '14 at 08:27
  • 1
    @ErdincAy I got them originally from the source of the [CalendarProvider](https://android.googlesource.com/platform/packages/providers/CalendarProvider/). If you browse to `CalendarProvider2.java` (`CalendarProvider.java` in earlier versions), and search for `addURI`, you can see the full list. – Markus Jarderot Dec 17 '14 at 09:07
  • 1
    thanks, i still dont understand why they use URIs for table names and table queries, ... uncomfortable – Erdinc Ay Dec 17 '14 at 09:40
  • 2
    I'd kill for a code snippet to iterate through recurring events. What is the following? `(now - window) + "/" + (now + window) ` What is now and window? I also don't even see where **getCalendarManagedCursor** comes from. This whole process of simply reading all events (including and most important RECURRING events) has been frustrating. Tons of partial code snippets, pseudo code, and links to tutorials. In the end, still can't show recurring events. – Herb Meehan Feb 13 '15 at 08:40
  • @MarkusJarderot is it possible to get original event duration (without query to `Instances`)? I suppose it should be possible as during creation I set **start** and **end** date for original event and based on it duration calculated for instances. Please check http://stackoverflow.com/questions/40221843/why-duration-is-null-for-recurrent-event-in-android – Natasha Oct 25 '16 at 08:14
  • @Natasha You have Instances (START, END) and Events (DTSTART, DTEND). Instances inherit all the columns from the Event it belongs to. The EVENT_ID column is the ID of the Event. If the event (or instance) is an exception of another event, it will have columns ORIGINAL_ID and ORIGINAL_INSTANCE_TIME. Look at [CalendarContract.Instances](https://developer.android.com/reference/android/provider/CalendarContract.Instances.html) and it's base classes for more information. – Markus Jarderot Oct 25 '16 at 09:34
  • @MarkusJarderot thanks a lot for reply. I know that `Instances` has all data from `Events` but I need just **duration** (which is the same for all instances). When I query event Instances it receive a lot of unnecessary records. All recurrent event instances has the same duration and based on RRULE (and other recurrence fields), DTSTART and duration I can calculate (START, END) pairs for all instances. In my app I want to have just Event but not X different event Instances. My question is can I get all necessary Event information (incl. single item duration) without query to Instances? – Natasha Oct 25 '16 at 09:58
  • @MarkusJarderot probably `CalendarContract.Events.DURATION` solves my problem. I have an issue with indexes. – Natasha Oct 25 '16 at 10:25
  • @HerbMeehan: I share your frustration deeply! It get's better the more you work with it. `now` is probably something like the current time `long now = new Date().getTime();` while `window` is some sort of time-frame i.e. `DateUtils.WEEK_IN_MILLIS`. So if you calculate `now - window` and `now + window`, you get all events that take place between 1 week in the past and 1 week into the future from now. Hope this helps! – hamena314 Apr 10 '17 at 10:28
4

I finally made this work in the following way. Remember DTSTART, DTEND, _ID don't work for Instances table even if you can access them. Use BEGIN, END and Event_ID instead. Please refer to these 2 links: How to get calendar events with title including recurring events and Android Calendar Recurring Events Have Wrong End Date/Time

        long now = System.currentTimeMillis();

        Uri.Builder eventsUriBuilder = CalendarContract.Instances.CONTENT_URI.buildUpon();
        ContentUris.appendId(eventsUriBuilder, Long.MIN_VALUE);
        ContentUris.appendId(eventsUriBuilder, Long.MAX_VALUE);

        Uri eventsUri = eventsUriBuilder.build();
        Cursor cursor = context.getContentResolver().query(
            eventsUri,
            new String[] {CalendarContract.Instances.CALENDAR_ID, CalendarContract.Instances.TITLE,
                    CalendarContract.Instances.DESCRIPTION, CalendarContract.Instances.BEGIN,
                    CalendarContract.Instances.END, CalendarContract.Instances.EVENT_LOCATION,
                    CalendarContract.Instances.EVENT_ID},
            CalendarContract.Instances.BEGIN + " >= " + now + " and " + CalendarContract.Instances.BEGIN 
                    + " <= " + (now + 2592000000L) + " and " + CalendarContract.Instances.VISIBLE + " = 1",
            null,
            CalendarContract.Instances.BEGIN + " ASC");
Community
  • 1
  • 1
Sean
  • 197
  • 2
  • 7