@Override public void populate(Resource resource) throws LocalStorageException { Event e = (Event) resource; try { @Cleanup Cursor cursor = providerClient.query( ContentUris.withAppendedId(entriesURI(), e.getLocalID()), new String[] { /* 0 */ Events.TITLE, Events.EVENT_LOCATION, Events.DESCRIPTION, /* 3 */ Events.DTSTART, Events.DTEND, Events.EVENT_TIMEZONE, Events.EVENT_END_TIMEZONE, Events.ALL_DAY, /* 8 */ Events.STATUS, Events.ACCESS_LEVEL, /* 10 */ Events.RRULE, Events.RDATE, Events.EXRULE, Events.EXDATE, /* 14 */ Events.HAS_ATTENDEE_DATA, Events.ORGANIZER, Events.SELF_ATTENDEE_STATUS, /* 17 */ entryColumnUID(), Events.DURATION, Events.AVAILABILITY }, null, null, null); if (cursor != null && cursor.moveToNext()) { e.setUid(cursor.getString(17)); e.setSummary(cursor.getString(0)); e.setLocation(cursor.getString(1)); e.setDescription(cursor.getString(2)); boolean allDay = cursor.getInt(7) != 0; long tsStart = cursor.getLong(3), tsEnd = cursor.getLong(4); String duration = cursor.getString(18); String tzId = null; if (allDay) { e.setDtStart(tsStart, null); // provide only DTEND and not DURATION for all-day events if (tsEnd == 0) { Dur dur = new Dur(duration); java.util.Date dEnd = dur.getTime(new java.util.Date(tsStart)); tsEnd = dEnd.getTime(); } e.setDtEnd(tsEnd, null); } else { // use the start time zone for the end time, too // because apps like Samsung Planner allow the user to change "the" time zone but change // the start time zone only tzId = cursor.getString(5); e.setDtStart(tsStart, tzId); if (tsEnd != 0) e.setDtEnd(tsEnd, tzId); else if (!StringUtils.isEmpty(duration)) e.setDuration(new Duration(new Dur(duration))); } // recurrence try { String strRRule = cursor.getString(10); if (!StringUtils.isEmpty(strRRule)) e.setRrule(new RRule(strRRule)); String strRDate = cursor.getString(11); if (!StringUtils.isEmpty(strRDate)) { RDate rDate = new RDate(); rDate.setValue(strRDate); e.setRdate(rDate); } String strExRule = cursor.getString(12); if (!StringUtils.isEmpty(strExRule)) { ExRule exRule = new ExRule(); exRule.setValue(strExRule); e.setExrule(exRule); } String strExDate = cursor.getString(13); if (!StringUtils.isEmpty(strExDate)) { // ignored, see https://code.google.com/p/android/issues/detail?id=21426 ExDate exDate = new ExDate(); exDate.setValue(strExDate); e.setExdate(exDate); } } catch (ParseException ex) { Log.w(TAG, "Couldn't parse recurrence rules, ignoring", ex); } catch (IllegalArgumentException ex) { Log.w(TAG, "Invalid recurrence rules, ignoring", ex); } // status switch (cursor.getInt(8)) { case Events.STATUS_CONFIRMED: e.setStatus(Status.VEVENT_CONFIRMED); break; case Events.STATUS_TENTATIVE: e.setStatus(Status.VEVENT_TENTATIVE); break; case Events.STATUS_CANCELED: e.setStatus(Status.VEVENT_CANCELLED); } // availability e.setOpaque(cursor.getInt(19) != Events.AVAILABILITY_FREE); // attendees if (cursor.getInt(14) != 0) { // has attendees try { e.setOrganizer(new Organizer(new URI("mailto", cursor.getString(15), null))); } catch (URISyntaxException ex) { Log.e(TAG, "Error when creating ORGANIZER URI, ignoring", ex); } populateAttendees(e); } // classification switch (cursor.getInt(9)) { case Events.ACCESS_CONFIDENTIAL: case Events.ACCESS_PRIVATE: e.setForPublic(false); break; case Events.ACCESS_PUBLIC: e.setForPublic(true); } populateReminders(e); } else throw new RecordNotFoundException(); } catch (RemoteException ex) { throw new LocalStorageException(ex); } }