mirror of
https://github.com/etesync/android
synced 2025-02-02 10:51:10 +00:00
Improved iCal generation
* move shared code to new iCalendar class * generate UIDs and file names with "_" instead of "@" to reduce encoding problems (closes #585) * tasks: validate "start date" and "completed at" time zones
This commit is contained in:
parent
9d76d57af8
commit
243483a957
@ -69,11 +69,9 @@ import lombok.NonNull;
|
||||
import lombok.Setter;
|
||||
|
||||
|
||||
public class Event extends Resource {
|
||||
public class Event extends iCalendar {
|
||||
private final static String TAG = "davdroid.Event";
|
||||
|
||||
private final static TimeZoneRegistry tzRegistry = new DefaultTimeZoneRegistryFactory().createRegistry();
|
||||
|
||||
@Getter @Setter protected RecurrenceId recurrenceId;
|
||||
|
||||
@Getter @Setter protected String summary, location, description;
|
||||
@ -97,15 +95,6 @@ public class Event extends Resource {
|
||||
|
||||
@Getter protected List<VAlarm> alarms = new LinkedList<>();
|
||||
|
||||
static {
|
||||
CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_UNFOLDING, true);
|
||||
CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING, true);
|
||||
CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_OUTLOOK_COMPATIBILITY, true);
|
||||
|
||||
// disable automatic time-zone updates (causes unnecessary network traffic for most people)
|
||||
System.setProperty("net.fortuna.ical4j.timezone.update.enabled", "false");
|
||||
}
|
||||
|
||||
|
||||
public Event(String name, String ETag) {
|
||||
super(name, ETag);
|
||||
@ -115,18 +104,6 @@ public class Event extends Resource {
|
||||
super(localID, name, ETag);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
generateUID();
|
||||
name = uid.replace("@", "_") + ".ics";
|
||||
}
|
||||
|
||||
protected void generateUID() {
|
||||
UidGenerator generator = new UidGenerator(new SimpleHostInfo(DavSyncAdapter.getAndroidID()), String.valueOf(android.os.Process.myPid()));
|
||||
uid = generator.generateUid().getValue();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -228,12 +205,6 @@ public class Event extends Resource {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getMimeType() {
|
||||
return "text/calendar";
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ByteArrayOutputStream toEntity() throws IOException {
|
||||
@ -333,7 +304,13 @@ public class Event extends Resource {
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// time helpers
|
||||
|
||||
public boolean isAllDay() {
|
||||
return !hasTime(dtStart);
|
||||
}
|
||||
|
||||
public long getDtStartInMillis() {
|
||||
return dtStart.getDate().getTime();
|
||||
}
|
||||
@ -370,54 +347,6 @@ public class Event extends Resource {
|
||||
dtEnd = new DtEnd(end);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// helpers
|
||||
|
||||
public boolean isAllDay() {
|
||||
return !hasTime(dtStart);
|
||||
}
|
||||
|
||||
protected static boolean hasTime(DateProperty date) {
|
||||
return date.getDate() instanceof DateTime;
|
||||
}
|
||||
|
||||
protected static String getTzId(DateProperty date) {
|
||||
if (date.isUtc() || !hasTime(date))
|
||||
return Time.TIMEZONE_UTC;
|
||||
else if (date.getTimeZone() != null)
|
||||
return date.getTimeZone().getID();
|
||||
else if (date.getParameter(Value.TZID) != null)
|
||||
return date.getParameter(Value.TZID).getValue();
|
||||
|
||||
// fallback
|
||||
return Time.TIMEZONE_UTC;
|
||||
}
|
||||
|
||||
/* guess matching Android timezone ID */
|
||||
protected static void validateTimeZone(DateProperty date) {
|
||||
if (date.isUtc() || !hasTime(date))
|
||||
return;
|
||||
|
||||
String tzID = getTzId(date);
|
||||
if (tzID == null)
|
||||
return;
|
||||
|
||||
String localTZ = DateUtils.findAndroidTimezoneID(tzID);
|
||||
date.setTimeZone(tzRegistry.getTimeZone(localTZ));
|
||||
}
|
||||
|
||||
public static String TimezoneDefToTzId(String timezoneDef) throws IllegalArgumentException {
|
||||
try {
|
||||
if (timezoneDef != null) {
|
||||
CalendarBuilder builder = new CalendarBuilder();
|
||||
net.fortuna.ical4j.model.Calendar cal = builder.build(new StringReader(timezoneDef));
|
||||
VTimeZone timezone = (VTimeZone)cal.getComponent(VTimeZone.VTIMEZONE);
|
||||
return timezone.getTimeZoneId().getValue();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.w(TAG, "Can't understand time zone definition, ignoring", ex);
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ import at.bitfire.davdroid.syncadapter.DavSyncAdapter;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class Task extends Resource {
|
||||
public class Task extends iCalendar {
|
||||
private final static String TAG = "davdroid.Task";
|
||||
|
||||
@Getter @Setter DateTime createdAt;
|
||||
@ -76,13 +76,6 @@ public class Task extends Resource {
|
||||
super(localId, name, ETag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
UidGenerator generator = new UidGenerator(new SimpleHostInfo(DavSyncAdapter.getAndroidID()), String.valueOf(android.os.Process.myPid()));
|
||||
uid = generator.generateUid().getValue();
|
||||
name = uid + ".ics";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void parseEntity(InputStream entity, AssetDownloader downloader) throws IOException, InvalidResourceException {
|
||||
@ -104,6 +97,10 @@ public class Task extends Resource {
|
||||
|
||||
if (todo.getUid() != null)
|
||||
uid = todo.getUid().getValue();
|
||||
else {
|
||||
Log.w(TAG, "Received VTODO without UID, generating new one");
|
||||
generateUID();
|
||||
}
|
||||
|
||||
if (todo.getCreated() != null)
|
||||
createdAt = todo.getCreated().getDateTime();
|
||||
@ -129,20 +126,19 @@ public class Task extends Resource {
|
||||
due = todo.getDue();
|
||||
if (todo.getDuration() != null)
|
||||
duration = todo.getDuration();
|
||||
if (todo.getStartDate() != null)
|
||||
if (todo.getStartDate() != null) {
|
||||
dtStart = todo.getStartDate();
|
||||
if (todo.getDateCompleted() != null)
|
||||
validateTimeZone(dtStart);
|
||||
}
|
||||
if (todo.getDateCompleted() != null) {
|
||||
completedAt = todo.getDateCompleted();
|
||||
validateTimeZone(completedAt);
|
||||
}
|
||||
if (todo.getPercentComplete() != null)
|
||||
percentComplete = todo.getPercentComplete().getPercentage();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getMimeType() {
|
||||
return "text/calendar";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteArrayOutputStream toEntity() throws IOException {
|
||||
final net.fortuna.ical4j.model.Calendar ical = new net.fortuna.ical4j.model.Calendar();
|
||||
|
123
app/src/main/java/at/bitfire/davdroid/resource/iCalendar.java
Normal file
123
app/src/main/java/at/bitfire/davdroid/resource/iCalendar.java
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering).
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the GNU Public License v3.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
|
||||
package at.bitfire.davdroid.resource;
|
||||
|
||||
import android.text.format.Time;
|
||||
import android.util.Log;
|
||||
|
||||
import net.fortuna.ical4j.data.CalendarBuilder;
|
||||
import net.fortuna.ical4j.model.DateTime;
|
||||
import net.fortuna.ical4j.model.DefaultTimeZoneRegistryFactory;
|
||||
import net.fortuna.ical4j.model.TimeZoneRegistry;
|
||||
import net.fortuna.ical4j.model.component.VTimeZone;
|
||||
import net.fortuna.ical4j.model.parameter.Value;
|
||||
import net.fortuna.ical4j.model.property.DateProperty;
|
||||
import net.fortuna.ical4j.model.property.DtStart;
|
||||
import net.fortuna.ical4j.util.CompatibilityHints;
|
||||
import net.fortuna.ical4j.util.SimpleHostInfo;
|
||||
import net.fortuna.ical4j.util.UidGenerator;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
|
||||
import at.bitfire.davdroid.DateUtils;
|
||||
import at.bitfire.davdroid.syncadapter.DavSyncAdapter;
|
||||
import lombok.Getter;
|
||||
|
||||
public abstract class iCalendar extends Resource {
|
||||
static private final String TAG = "DAVdroid.iCal";
|
||||
|
||||
// static ical4j initialization
|
||||
static {
|
||||
CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_UNFOLDING, true);
|
||||
CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING, true);
|
||||
CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_OUTLOOK_COMPATIBILITY, true);
|
||||
|
||||
// disable automatic time-zone updates (causes unwanted network traffic)
|
||||
System.setProperty("net.fortuna.ical4j.timezone.update.enabled", "false");
|
||||
}
|
||||
|
||||
static protected final TimeZoneRegistry tzRegistry = new DefaultTimeZoneRegistryFactory().createRegistry();
|
||||
|
||||
|
||||
public iCalendar(long localID, String name, String ETag) {
|
||||
super(localID, name, ETag);
|
||||
}
|
||||
|
||||
public iCalendar(String name, String ETag) {
|
||||
super(name, ETag);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
generateUID();
|
||||
name = uid + ".ics";
|
||||
}
|
||||
|
||||
protected void generateUID() {
|
||||
UidGenerator generator = new UidGenerator(new SimpleHostInfo(DavSyncAdapter.getAndroidID()), String.valueOf(android.os.Process.myPid()));
|
||||
uid = generator.generateUid().getValue().replace("@", "_");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getMimeType() {
|
||||
return "text/calendar";
|
||||
}
|
||||
|
||||
|
||||
// time zone helpers
|
||||
|
||||
protected static boolean hasTime(DateProperty date) {
|
||||
return date.getDate() instanceof DateTime;
|
||||
}
|
||||
|
||||
protected static String getTzId(DateProperty date) {
|
||||
if (date.isUtc() || !hasTime(date))
|
||||
return Time.TIMEZONE_UTC;
|
||||
else if (date.getTimeZone() != null)
|
||||
return date.getTimeZone().getID();
|
||||
else if (date.getParameter(Value.TZID) != null)
|
||||
return date.getParameter(Value.TZID).getValue();
|
||||
|
||||
// fallback
|
||||
return Time.TIMEZONE_UTC;
|
||||
}
|
||||
|
||||
/* guess matching Android timezone ID */
|
||||
protected static void validateTimeZone(DateProperty date) {
|
||||
if (date.isUtc() || !hasTime(date))
|
||||
return;
|
||||
|
||||
String tzID = getTzId(date);
|
||||
if (tzID == null)
|
||||
return;
|
||||
|
||||
String localTZ = DateUtils.findAndroidTimezoneID(tzID);
|
||||
date.setTimeZone(tzRegistry.getTimeZone(localTZ));
|
||||
}
|
||||
|
||||
public static String TimezoneDefToTzId(String timezoneDef) throws IllegalArgumentException {
|
||||
try {
|
||||
if (timezoneDef != null) {
|
||||
CalendarBuilder builder = new CalendarBuilder();
|
||||
net.fortuna.ical4j.model.Calendar cal = builder.build(new StringReader(timezoneDef));
|
||||
VTimeZone timezone = (VTimeZone)cal.getComponent(VTimeZone.VTIMEZONE);
|
||||
return timezone.getTimeZoneId().getValue();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.w(TAG, "Can't understand time zone definition, ignoring", ex);
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user