Sunday, November 24, 2013

Android Calendar Provider Instances Query on Legacy systems

I have run into a strange problem, when querying the Instances URI of Androids Calendar Provider on older Android versions. I was trying to get event instances from a given calendar (with id and planerCalendardId) and restrict to instances whose begin date is between two values, but the following query stubbornly refused to return any results:

    String[] INSTANCE_PROJECTION = new String[] {
          Instances.EVENT_ID,
          Instances._ID
        };
      Uri.Builder eventsUriBuilder = CalendarContractCompat.Instances.CONTENT_URI
          .buildUpon();
      ContentUris.appendId(eventsUriBuilder, lastExecutionTimeStamp);
      ContentUris.appendId(eventsUriBuilder, now);
      Uri eventsUri = eventsUriBuilder.build();
      //Instances.Content_URI returns events that fall totally or partially in a given range
      //we additionally select only instances where the begin is inside the range
      //because we want to deal with each instance only once
      Cursor cursor = getContentResolver().query(eventsUri, INSTANCE_PROJECTION,
          Events.CALENDAR_ID + " = ? AND "+ Instances.BEGIN + " BETWEEN ? AND ?",
          new String[]{
            planerCalendarId,
            String.valueOf(lastExecutionTimeStamp),
            String.valueOf(now)},
            null);

After banging my head for some time in different directions, I found out that only inspecting the source makes the behaviour understandable. Older versions of the Calendar provider, incorrectly handle the selection arguments passed in, in fact they throw them away. As can be seen in http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android-apps/2.2_r1.1/com/android/providers/calendar/CalendarProvider2.java on lines 660,661, the selectionArgs parameter to the query method is simply not passed to handleInstanceQuery.
The problem can be worked around by merging the selection arguments into the selection.

      Cursor cursor = getContentResolver().query(eventsUri, INSTANCE_PROJECTION,
          Events.CALENDAR_ID + " = " + planerCalendarId + " AND "+ Instances.BEGIN +
              " BETWEEN " + lastExecutionTimeStamp + " AND " + now,
          null,
          null);

No comments:

Post a Comment