5

I am working on an Android application. I have to add events to native Android calendar. So I tried the following code:

if (Build.VERSION.SDK_INT >= 8 ) {
    l_eventUri = Uri.parse("content://com.android.calendar/events");
} else {
    l_eventUri = Uri.parse("content://calendar/events");
}

Cursor cursor = getContentResolver() .query(Uri.parse(getCalendarUriBase(this)),new String[] { "calendar_id", "displayname"}, null,null, null);
cursor.moveToFirst();
// fetching calendars name
String CNames[] = new String[cursor.getCount()];
// fetching calendars id
int[] CalIds = new int[cursor.getCount()];
for (int i = 0; i < CNames.length; i++) {
    CalIds[i] = cursor.getInt(0);
    CNames[i] = cursor.getString(1);
    cursor.moveToNext();
}

// get calendar
Calendar cal = Calendar.getInstance();     
Uri EVENTS_URI = Uri.parse(getCalendarUriBase(this) + "events");
ContentResolver cr = getContentResolver();

// event insert
ContentValues values = new ContentValues();
values.put("calendar_id",111);
values.put("title", "Reminder Title");
values.put("allDay", 0);
values.put("dtstart", cal.getTimeInMillis() + 11*60*1000); // event starts at 11 minutes from now
values.put("dtend", cal.getTimeInMillis()+60*60*1000); // ends 60 minutes from now
values.put("description", "Reminder description");
//Event Id
values.put("_id", 23);  
//0~ default; 1~ confidential; 2~ private; 3~ public
values.put("visibility", 0);
//0~ false; 1~ true
values.put("hasAlarm", 1);
//status: 0~ tentative; 1~ confirmed; 2~ canceled
values.put("eventStatus", 1);
//0~ opaque, no timing conflict is allowed; 1~ transparency, allow overlap of scheduling
values.put("transparency", 0);
Uri event = cr.insert(EVENTS_URI, values);

// reminder insert
Uri REMINDERS_URI = Uri.parse(getCalendarUriBase(this) + "reminders");
values = new ContentValues();
values.put( "event_id", Long.parseLong(event.getLastPathSegment()));
values.put( "method", 1 );
values.put( "minutes", 10 );
cr.insert( REMINDERS_URI, values );

private String getCalendarUriBase(Activity act) {
    String calendarUriBase = null;
    Uri calendars = Uri.parse("content://calendar/calendars");
    Cursor managedCursor = null;
    try {
        managedCursor = act.managedQuery(calendars, null, null, null, null);
    } catch (Exception e) {
    }

    if (managedCursor != null) {
        calendarUriBase = "content://calendar/";
    } else {
        calendars = Uri.parse("content://com.android.calendar/calendars");
        try {
            managedCursor = act.managedQuery(calendars, null, null, null, null);
        } catch (Exception e) {
        }
        if (managedCursor != null) {
            calendarUriBase = "content://com.android.calendar/";
        }
    }
    return calendarUriBase;
}

When I run this code, I am getting the IllegalArgumentException.

java.lang.IllegalArgumentException: Unknown URL content://com.android.calendar/

I think the error is because of getCalendarUriBase() method. I searched a lot for other ways, but so far most of the developers following the above code snippet because this will work for every Android versions. How to fix it?

Andrew T.
  • 4,701
  • 8
  • 43
  • 62
sarath
  • 3,181
  • 7
  • 36
  • 58

1 Answers1

3

You missed calendars when you try to execute this line

Cursor cursor = getContentResolver().query(
    Uri.parse(getCalendarUriBase(this)), /* <-- unknown URL content */
    new String[] { "calendar_id", "displayname" },
    null,null,null);

resulting in IllegalArgumentException.

Just add the calendars after getCalendarUriBase(this).

Cursor cursor = getContentResolver().query(
    Uri.parse(getCalendarUriBase(this)+"calendars"),
    new String[] { "_id", "displayName" },
    null,null,null);

Note:

  • Use _id to get the calendar ID if you query from calendars table. calendar_id is defined as a foreign key in other tables (e.g. events).
  • Use displayName for GingerBread or below. For Ice Cream Sandwich and above, use calendar_displayName.

When adding an event, you need to include: calendar ID, start date, end date (or recurrence rule), and event timezone. You have included all but the timezone. Try adding

values.put("eventTimezone", TimeZone.getDefault().getID());

before inserting the event.

Andrew T.
  • 4,701
  • 8
  • 43
  • 62
  • @Andrew..Thank you very much..now I am getting 1android.database.sqlite.SQLiteException: no such column: calendar_id (code 1): , while compiling: SELECT calendar_id, displayname FROM Calendars..Please help me to fix this issue too... – sarath Nov 21 '13 at 06:34
  • Edited the code. Added some info you need to know regarding the calendar provider. – Andrew T. Nov 21 '13 at 06:44
  • Hi Andrew..now the code is working but no events are created in calender...what I have to do? – sarath Nov 21 '13 at 07:08
  • First, check whether the `calendar_id` is correct or not. Second, you also need to define the time-zone for the event. Try adding `values.put("eventTimezone", TimeZone.getDefault().getID());` – Andrew T. Nov 21 '13 at 07:39
  • I already added eventtimezone and where I have to change calender_id?..I changed here Cursor cursor = getContentResolver() .query(Uri.parse(getCalendarUriBase(this)+"calendars" ),new String[] { "_id", "displayName" }, null,null, null);...In valued I am addind both calender_id and _id...there I had given some number .. – sarath Nov 21 '13 at 07:50
  • Check the `calendar_id` on this line: `values.put("calendar_id",111);`. For a test, try this instead `values.put("calendar_id",CalIds[0]);` to insert the event to the first calendar from the query. – Andrew T. Nov 21 '13 at 07:54
  • now I got nullpointer exception for values.put( "event_id", Long.parseLong(event.getLastPathSegment()));.. – sarath Nov 21 '13 at 08:38
  • I see. That means 111 is valid for `calendar_id`. With current condition, I couldn't analyze why the event is not created. As the comments are already quite long, I suggest you to create new question regarding this issue (event not created) with the updated code. – Andrew T. Nov 21 '13 at 09:03