Process multiple RDATE/EXDATE values (see #340, see #495)

pull/2/head
Ricki Hirner 9 years ago
parent 97633c5204
commit 87df8f880d

@ -59,6 +59,7 @@ import java.io.InputStream;
import java.io.StringReader;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@ -85,9 +86,9 @@ public class Event extends Resource {
@Getter protected DtStart dtStart;
@Getter protected DtEnd dtEnd;
@Getter @Setter protected Duration duration;
@Getter @Setter protected RDate rdate;
@Getter protected List<RDate> rdates = new LinkedList<>();
@Getter @Setter protected RRule rrule;
@Getter @Setter protected ExDate exdate;
@Getter protected List<ExDate> exdates = new LinkedList<>();
@Getter @Setter protected ExRule exrule;
@Getter protected List<Event> exceptions = new LinkedList<>();
@ -152,27 +153,23 @@ public class Event extends Resource {
// find master VEVENT (the one that is not an exception, i.e. the one without RECURRENCE-ID)
VEvent master = null;
for (Object objEvent : events) {
VEvent event = (VEvent)objEvent;
for (VEvent event : (Iterable<VEvent>)events)
if (event.getRecurrenceId() == null) {
master = event;
break;
}
}
if (master == null)
throw new InvalidResourceException("No VEVENT without RECURRENCE-ID found");
// set event data from master VEVENT
fromVEvent(master);
// find and process exceptions
for (Object objEvent : events) {
VEvent event = (VEvent)objEvent;
for (VEvent event : (Iterable<VEvent>)events)
if (event.getRecurrenceId() != null) {
Event exception = new Event(name, null);
exception.fromVEvent(event);
exceptions.add(exception);
}
}
}
protected void fromVEvent(VEvent event) throws InvalidResourceException {
@ -204,9 +201,11 @@ public class Event extends Resource {
}
rrule = (RRule)event.getProperty(Property.RRULE);
rdate = (RDate)event.getProperty(Property.RDATE);
for (RDate rdate : (Iterable<RDate>)event.getProperties(Property.RDATE))
rdates.add(rdate);
exrule = (ExRule)event.getProperty(Property.EXRULE);
exdate = (ExDate)event.getProperty(Property.EXDATE);
for (ExDate exdate : (Iterable<ExDate>)event.getProperties(Property.EXDATE))
exdates.add(exdate);
if (event.getSummary() != null)
summary = event.getSummary().getValue();
@ -219,8 +218,8 @@ public class Event extends Resource {
opaque = event.getTransparency() != Transp.TRANSPARENT;
organizer = event.getOrganizer();
for (Object o : event.getProperties(Property.ATTENDEE))
attendees.add((Attendee)o);
for (Attendee attendee : (Iterable<Attendee>)event.getProperties(Property.ATTENDEE))
attendees.add(attendee);
Clazz classification = event.getClassification();
if (classification != null) {
@ -307,11 +306,11 @@ public class Event extends Resource {
if (rrule != null)
props.add(rrule);
if (rdate != null)
for (RDate rdate : rdates)
props.add(rdate);
if (exrule != null)
props.add(exrule);
if (exdate != null)
for (ExDate exdate : exdates)
props.add(exdate);
if (summary != null && !summary.isEmpty())

@ -32,10 +32,13 @@ import android.provider.ContactsContract;
import android.util.Log;
import net.fortuna.ical4j.model.Date;
import net.fortuna.ical4j.model.DateList;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.Dur;
import net.fortuna.ical4j.model.Parameter;
import net.fortuna.ical4j.model.ParameterList;
import net.fortuna.ical4j.model.Period;
import net.fortuna.ical4j.model.PeriodList;
import net.fortuna.ical4j.model.PropertyList;
import net.fortuna.ical4j.model.TimeZone;
import net.fortuna.ical4j.model.TimeZoneRegistry;
@ -47,6 +50,8 @@ import net.fortuna.ical4j.model.parameter.PartStat;
import net.fortuna.ical4j.model.parameter.Role;
import net.fortuna.ical4j.model.property.Action;
import net.fortuna.ical4j.model.property.Attendee;
import net.fortuna.ical4j.model.property.DateListProperty;
import net.fortuna.ical4j.model.property.DateProperty;
import net.fortuna.ical4j.model.property.Description;
import net.fortuna.ical4j.model.property.Duration;
import net.fortuna.ical4j.model.property.ExDate;
@ -288,7 +293,7 @@ public class LocalCalendar extends LocalCollection<Event> {
pendingOperations.add(ContentProviderOperation
.newUpdate(entriesURI())
.withValue(Events.DIRTY, 0)
.withSelection(Events.ORIGINAL_ID + "=?", new String[]{ String.valueOf(resource.getLocalID()) })
.withSelection(Events.ORIGINAL_ID + "=?", new String[]{String.valueOf(resource.getLocalID())})
.build()
);
}
@ -373,7 +378,7 @@ public class LocalCalendar extends LocalCollection<Event> {
if (!StringUtils.isEmpty(strRDate)) {
RDate rDate = new RDate();
rDate.setValue(strRDate);
e.setRdate(rDate);
e.getRdates().add(rDate);
}
String strExRule = values.getAsString(Events.EXRULE);
@ -385,10 +390,10 @@ public class LocalCalendar extends LocalCollection<Event> {
String strExDate = values.getAsString(Events.EXDATE);
if (!StringUtils.isEmpty(strExDate)) {
// ignored, see https://code.google.com/p/android/issues/detail?id=21426
// always empty, see https://code.google.com/p/android/issues/detail?id=172411
ExDate exDate = new ExDate();
exDate.setValue(strExDate);
e.setExdate(exDate);
e.getExdates().add(exDate);
}
} catch (ParseException ex) {
Log.w(TAG, "Couldn't parse recurrence rules, ignoring", ex);
@ -558,24 +563,15 @@ public class LocalCalendar extends LocalCollection<Event> {
recurring = true;
builder = builder.withValue(Events.RRULE, event.getRrule().getValue());
}
if (event.getRdate() != null) {
if (!event.getRdates().isEmpty()) {
recurring = true;
RDate rDate = event.getRdate();
String rDateStr = rDate.getValue();
if (rDate.getTimeZone() != null)
rDateStr = DateUtils.findAndroidTimezoneID(rDate.getTimeZone().getID()) + ";" + rDateStr;
builder = builder.withValue(Events.RDATE, rDateStr);
builder = builder.withValue(Events.RDATE, recurrenceSetsToAndroidString(event.getRdates()));
}
if (event.getExrule() != null)
builder = builder.withValue(Events.EXRULE, event.getExrule().getValue());
if (event.getExdate() != null) {
ExDate exDate = event.getExdate();
String exDateStr = exDate.getValue();
if (exDate.getTimeZone() != null)
exDateStr = DateUtils.findAndroidTimezoneID(exDate.getTimeZone().getID()) + ";" + exDateStr;
builder = builder.withValue(Events.EXDATE, exDateStr);
}
if (!event.getExdates().isEmpty())
builder = builder.withValue(Events.EXDATE, recurrenceSetsToAndroidString(event.getExdates()));
// set either DTEND for single-time events or DURATION for recurring events
// because that's the way Android likes it (see docs)
if (recurring) {
@ -758,4 +754,34 @@ public class LocalCalendar extends LocalCollection<Event> {
return calendarsURI(account);
}
/**
* Concatenates, if necessary, multiple RDATE/EXDATE lists and prepares
* a formatted string as expected by Android calendar provider
* @param dates one more more lists of RDATE or EXDATE
* @return formatted string for Android calendar provider
*/
protected static String recurrenceSetsToAndroidString(List<? extends DateListProperty> dates) {
String tzID = null;
List<String> strDates = new LinkedList<String>();
for (DateListProperty dateList : dates) {
if (dateList.getTimeZone() != null) {
String thisTzID = DateUtils.findAndroidTimezoneID(dateList.getTimeZone().getID());
if (tzID == null)
tzID = thisTzID;
else if (!tzID.equals(thisTzID))
Log.w(TAG, "Multiple EXDATEs/RDATEs with different time zones not supported by Android, using " + tzID + " for all dates");
}
strDates.add(dateList.getValue());
}
// Android expects this format: "[TZID;]date1,date2,date3"
String dateStr = "";
if (tzID != null)
dateStr += tzID + ";";
dateStr += StringUtils.join(strDates, ",");
return dateStr;
}
}

Loading…
Cancel
Save