Stuart McLaren
Stuart McLaren

Reputation: 119

Delete only one instance of a recurring event from my Android calendar

I've been looking through the various posts on how to delete just one instance of a recurring event from my Android 2.3 Phone's calendar, but I haven't been able to find the perfect answer. So far, the best I've come across is :

Uri eventsUri = Uri.parse("content://com.android.calendar/events");
Uri deleteEventUri = Uri.withAppendedPath(eventsUri, String.valueOf(id2));
DeleteEventActivity.context.getContentResolver().delete(deleteEventUri, null, null);

Where id2 is the id of the event I want to delete. The problem I have is that I only want to delete one instance of a recurring event, but this code deletes all occurrences. Is there a way to delete only one instance? Thanks.

Upvotes: 5

Views: 3349

Answers (4)

Meisam Seyed Aliroteh
Meisam Seyed Aliroteh

Reputation: 599

What about updating particular instances of a recurring event? Say I have a daily recurring event Mon-Fri, but I want to update a few fields (begin, end/duration, title, description, all-day, availability, status) for the instance on Wed only. How can this be done?

I tried the approach that @alex-f mentioned:

  1. Find the instances for Wed
  2. Created an exception URI with appended ID.
  3. Created ContentValues and put BEGIN as ORIGINAL_INSTANCE_TIME.
  4. I didn't touch STATUS since I want to update not delete.
  5. I also put all other updated values in my ContentValues
  6. Execute insert(uri, values)

But this screwed up my event data:

  1. When I launched Google Calendar app I see that the event on Mon & Tue are no longer there
  2. Instead of only updating the Wed event, Wed+Thu+Fri instances all show updated data

Upvotes: 0

Stuart McLaren
Stuart McLaren

Reputation: 119

If anyone else is still struggling with this, I've finally cracked it!

It turns out that you do not delete or amend any records, what you actually do is insert a new event called an exception. It took me a few months to find this information anywhere, and even having found it, another few months to work out exactly what needed to be put into the exception to make it work, so here is how I did it.

Firstly, query the actual instance of the event that you want to cancel one occurrence of. You need to query the table CalendarContract.Instances to get the values of CalendarContract.Instances.TITLE, CalendarContract.Instances.BEGIN and CalendarContract.Instances.EVENT_ID. The way I do this in my code doesn't really fit in with the context of this answer, so hopefully you will be able to work out how to do that yourself. Store these values as:

final String title = eventCursor.getString(0); final long beginl=eventCursor.getLong(1); final int id = eventCursor.getInt(2);

Then we need to set up a new event as follows :

 final Context context = getApplicationContext();
 final ContentResolver contentResolver = context.getContentResolver();
 final Uri.Builder builder = Uri.parse(
"content://com.android.calendar/events").buildUpon();
 final Cursor eventCursor = contentResolver.query(builder.build(),
new String[] 
   {Events.CALENDAR_TIME_ZONE,Events.ALL_DAY,Events.CALENDAR_ID,Events._SYNC_ID,     Events.OWNER_ACCOUNT }, 
   "_id=" + id, null, null);
 while (eventCursor.moveToNext()) {
final String timezone=eventCursor.getString(0);
final String allday=eventCursor.getString(1);
final long calID=eventCursor.getLong(2);
final String mSyncId=eventCursor.getString(3);
final String account=eventCursor.getString(4);
ContentValues values = new ContentValues();
    values.put(Events.TITLE, title);
    values.put(Events.EVENT_TIMEZONE, timezone);
values.put(Events.ORIGINAL_SYNC_ID, mSyncId);//not 100% sure about this,may also need a date?
values.put(Events.HAS_ALARM, "0");
values.put(Events.HAS_ATTENDEE_DATA,"0");
values.put(Events.ALL_DAY, allday);
    values.put(Events.DTSTART, beginl+3600000);
    values.put(Events.ORIGINAL_INSTANCE_TIME, beginl+3600000);
values.put(Events.STATUS, Events.STATUS_CANCELED);
Uri uri = Uri.withAppendedPath(Events.CONTENT_EXCEPTION_URI,
        String.valueOf(id));
uri = asSyncAdapter(uri, account, CTS_TEST_TYPE);
Uri resultUri = context.getContentResolver().insert(uri, values);
    try {
        int eventID = Integer.parseInt(resultUri.getLastPathSegment()); 
        int debug=eventID;
        } catch (Exception e) {
        int debug=0;
        }
}
static Uri asSyncAdapter(Uri uri, String account, String accountType) {
    return uri.buildUpon()  
    .appendQueryParameter
        (android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true")
    .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
    .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
}

Hope this works, I've tried to cut out the parts of my code which are not relevant. You'll note I am having to add 3600000 to the beginl value (1 hour in milliseconds). I assume that is because we are in BST at the moment and this code will not work once the clocks change, but I'll worry about that at the time!

Finally, I used an app called Content Provider Helper to help me find this out. You can use it query your content provider tables. I would try setting up an exception using my code, then use my phones calendar app to delete the instance, and compare the two records.

Upvotes: 6

Alex.F
Alex.F

Reputation: 6181

Here are the basics

  1. Find the instance you want to delete. (using Instances.query())
  2. Create the exception URI with the event ID appended.
  3. Create ContentValues. Put your instance's BEGIN value as ...Events.ORIGINAL_INSTANCE_TIME. Put STATUS_CANCELED as ...Events.STATUS
  4. Now only insert(yourURI, yourValues) and that's it!

Upvotes: 6

Christopher Masser
Christopher Masser

Reputation: 829

You will have to update the EXDATE column of the original event.

Upvotes: 1

Related Questions