/** * Copyright (c) 2012-2013, Gerald Garcia, Timo Berger * * This file is part of Andoid Caldav Sync Adapter Free. * * Andoid Caldav Sync Adapter Free is free software: you can redistribute * it and/or modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 of the * License, or at your option any later version. * * Andoid Caldav Sync Adapter Free is distributed in the hope that * it will be useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Andoid Caldav Sync Adapter Free. * If not, see <http://www.gnu.org/licenses/>. * */ package org.gege.caldavsyncadapter.android.entities; import java.net.URISyntaxException; import java.text.ParseException; import net.fortuna.ical4j.model.Calendar; import net.fortuna.ical4j.model.Component; import net.fortuna.ical4j.model.ComponentList; import net.fortuna.ical4j.model.Date; import net.fortuna.ical4j.model.DateTime; import net.fortuna.ical4j.model.Dur; import net.fortuna.ical4j.model.ParameterList; import net.fortuna.ical4j.model.Property; import net.fortuna.ical4j.model.PropertyList; import net.fortuna.ical4j.model.TimeZone; import net.fortuna.ical4j.model.TimeZoneRegistry; import net.fortuna.ical4j.model.TimeZoneRegistryFactory; import net.fortuna.ical4j.model.component.VAlarm; import net.fortuna.ical4j.model.component.VEvent; import net.fortuna.ical4j.model.parameter.Cn; import net.fortuna.ical4j.model.parameter.PartStat; import net.fortuna.ical4j.model.parameter.Role; import net.fortuna.ical4j.model.parameter.Rsvp; import net.fortuna.ical4j.model.parameter.Value; import net.fortuna.ical4j.model.property.Action; import net.fortuna.ical4j.model.property.Attendee; import net.fortuna.ical4j.model.property.CalScale; import net.fortuna.ical4j.model.property.Clazz; import net.fortuna.ical4j.model.property.Description; import net.fortuna.ical4j.model.property.DtEnd; import net.fortuna.ical4j.model.property.DtStart; import net.fortuna.ical4j.model.property.Duration; import net.fortuna.ical4j.model.property.ExDate; import net.fortuna.ical4j.model.property.ExRule; import net.fortuna.ical4j.model.property.Location; import net.fortuna.ical4j.model.property.Organizer; import net.fortuna.ical4j.model.property.ProdId; import net.fortuna.ical4j.model.property.RDate; import net.fortuna.ical4j.model.property.RRule; import net.fortuna.ical4j.model.property.Status; import net.fortuna.ical4j.model.property.Summary; import net.fortuna.ical4j.model.property.Trigger; import net.fortuna.ical4j.model.property.Uid; import net.fortuna.ical4j.model.property.Version; //import android.accounts.Account; //import android.content.ContentProviderClient; //import android.content.ContentValues; //import android.content.SyncStats; import android.database.Cursor; import android.net.Uri; //import android.os.RemoteException; import android.provider.CalendarContract.Attendees; //import android.provider.CalendarContract.Calendars; import android.provider.CalendarContract.Events; import android.provider.CalendarContract.Reminders; //import org.gege.caldavsyncadapter.Event; //import org.gege.caldavsyncadapter.caldav.CaldavFacade; import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent; //import org.gege.caldavsyncadapter.caldav.entities.DavCalendar; //import org.gege.caldavsyncadapter.syncadapter.SyncAdapter; public class AndroidEvent extends org.gege.caldavsyncadapter.Event { private Uri muri; private Uri mAndroidCalendarUri; /** * the list of attendees */ private PropertyList mAttendees = new PropertyList(); /** * the list of reminders */ private ComponentList mReminders = new ComponentList(); private Calendar mCalendar = null; /* private Account mAccount = null; private ContentProviderClient mProvider = null;*/ //public AndroidEvent(Account account, ContentProviderClient provider, Uri uri, Uri calendarUri) { public AndroidEvent(Uri uri, Uri calendarUri) { super(); this.setUri(uri); /* this.mAccount = account; this.mProvider = provider;*/ //this.setCounterpartUri(calendarUri); mAndroidCalendarUri = calendarUri; } public Calendar getIcsEvent() { return mCalendar; } public String getETag() { String Result = ""; if (this.ContentValues.containsKey(ETAG)) Result = this.ContentValues.getAsString(ETAG); return Result; } public void setETag(String eTag) { this.ContentValues.put(ETAG, eTag); } public Uri getUri() { return muri; } public void setUri(Uri uri) { this.muri = uri; } public Uri getAndroidCalendarUri() { return mAndroidCalendarUri; } @Override public String toString() { return this.getUri().toString(); } /** * reads an android event from a given cursor into {@link AndroidEvent#ContentValues} * @param cur the cursor with the event * @return success of this funtion * @see AndroidEvent#ContentValues */ public boolean readContentValues(Cursor cur) { this.setETag(cur.getString(cur.getColumnIndex(ETAG))); this.ContentValues.put(Events.EVENT_TIMEZONE, cur.getString(cur.getColumnIndex(Events.EVENT_TIMEZONE))); this.ContentValues.put(Events.EVENT_END_TIMEZONE, cur.getString(cur.getColumnIndex(Events.EVENT_END_TIMEZONE))); this.ContentValues.put(Events.DTSTART, cur.getLong(cur.getColumnIndex(Events.DTSTART))); this.ContentValues.put(Events.DTEND, cur.getLong(cur.getColumnIndex(Events.DTEND))); this.ContentValues.put(Events.ALL_DAY, cur.getLong(cur.getColumnIndex(Events.ALL_DAY))); this.ContentValues.put(Events.TITLE, cur.getString(cur.getColumnIndex(Events.TITLE))); this.ContentValues.put(Events.CALENDAR_ID, cur.getString(cur.getColumnIndex(Events.CALENDAR_ID))); this.ContentValues.put(Events._SYNC_ID, cur.getString(cur.getColumnIndex(Events._SYNC_ID))); //this.ContentValues.put(Events.SYNC_DATA1, cur.getString(cur.getColumnIndex(Events.SYNC_DATA1))); //not needed here, eTag has already been read this.ContentValues.put(Events.DESCRIPTION, cur.getString(cur.getColumnIndex(Events.DESCRIPTION))); this.ContentValues.put(Events.EVENT_LOCATION, cur.getString(cur.getColumnIndex(Events.EVENT_LOCATION))); this.ContentValues.put(Events.ACCESS_LEVEL, cur.getInt(cur.getColumnIndex(Events.ACCESS_LEVEL))); this.ContentValues.put(Events.STATUS, cur.getInt(cur.getColumnIndex(Events.STATUS))); this.ContentValues.put(Events.LAST_DATE, cur.getInt(cur.getColumnIndex(Events.LAST_DATE))); this.ContentValues.put(Events.DURATION, cur.getString(cur.getColumnIndex(Events.DURATION))); this.ContentValues.put(Events.RDATE, cur.getString(cur.getColumnIndex(Events.RDATE))); this.ContentValues.put(Events.RRULE, cur.getString(cur.getColumnIndex(Events.RRULE))); this.ContentValues.put(Events.EXRULE, cur.getString(cur.getColumnIndex(Events.EXRULE))); this.ContentValues.put(Events.EXDATE, cur.getString(cur.getColumnIndex(Events.EXDATE))); this.ContentValues.put(Events.DIRTY, cur.getInt(cur.getColumnIndex(Events.DIRTY))); this.ContentValues.put(UID, cur.getString(cur.getColumnIndex(UID))); this.ContentValues.put(RAWDATA, cur.getString(cur.getColumnIndex(RAWDATA))); return true; } /** * reads the attendees from a given cursor * @param cur the cursor with the attendees * @return success of this function * @see AndroidEvent#mAttendees */ public boolean readAttendees(Cursor cur) { Attendee attendee = null; Organizer organizer = null; ParameterList paraList = null; String Name = ""; Cn cn = null; String Email = ""; int Relationship = 0; int Status = 0; PartStat partstat = null; int Type = 0; Role role = null; try { while (cur.moveToNext()) { Name = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_NAME)); Email = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_EMAIL)); Relationship = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_RELATIONSHIP)); Type = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_TYPE)); Status = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_STATUS)); if (Relationship == Attendees.RELATIONSHIP_ORGANIZER) { organizer = new Organizer(); organizer.setValue("mailto:" + Email); paraList = organizer.getParameters(); mAttendees.add(organizer); } else { attendee = new Attendee(); attendee.setValue("mailto:" + Email); paraList = attendee.getParameters(); mAttendees.add(attendee); } Rsvp rsvp = new Rsvp(true); paraList.add(rsvp); cn = new Cn(Name); paraList.add(cn); if (Status == Attendees.ATTENDEE_STATUS_INVITED) partstat = new PartStat(PartStat.NEEDS_ACTION.getValue()); else if (Status == Attendees.ATTENDEE_STATUS_ACCEPTED) partstat = new PartStat(PartStat.ACCEPTED.getValue()); else if (Status == Attendees.ATTENDEE_STATUS_DECLINED) partstat = new PartStat(PartStat.DECLINED.getValue()); else if (Status == Attendees.ATTENDEE_STATUS_NONE) partstat = new PartStat(PartStat.COMPLETED.getValue()); else if (Status == Attendees.ATTENDEE_STATUS_TENTATIVE) partstat = new PartStat(PartStat.TENTATIVE.getValue()); else partstat = new PartStat(PartStat.NEEDS_ACTION.getValue()); paraList.add(partstat); if (Type == Attendees.TYPE_OPTIONAL) role = new Role(Role.OPT_PARTICIPANT.getValue()); else if (Type == Attendees.TYPE_NONE) role = new Role(Role.NON_PARTICIPANT.getValue()); //regular participants in android are non required? else if (Type == Attendees.TYPE_REQUIRED) role = new Role(Role.REQ_PARTICIPANT.getValue()); else role = new Role(Role.NON_PARTICIPANT.getValue()); paraList.add(role); } } catch (URISyntaxException e) { e.printStackTrace(); } return true; } /** * reads the reminders from a given cursor * @param cur the cursor with the reminders * @return success of this function */ public boolean readReminder(Cursor cur) { int Method; int Minutes; VAlarm reminder; while (cur.moveToNext()) { reminder = new VAlarm(); Method = cur.getInt(cur.getColumnIndex(Reminders.METHOD)); Minutes = cur.getInt(cur.getColumnIndex(Reminders.MINUTES)) * -1; Dur dur = new Dur(0, 0, Minutes, 0); Trigger tri = new Trigger(dur); Value val = new Value(Duration.DURATION); tri.getParameters().add(val); reminder.getProperties().add(tri); Description desc = new Description(); desc.setValue("caldavsyncadapter standard description"); reminder.getProperties().add(desc); if (Method == Reminders.METHOD_EMAIL) reminder.getProperties().add(Action.EMAIL); else reminder.getProperties().add(Action.DISPLAY); this.mReminders.add(reminder); } return true; } /** * generates a new ics-file. * uses {@link AndroidEvent#ContentValues} as source. * this should only be used when a new event has been generated within android. * @param strUid the UID for this event. example: UID:e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter * @return success of the function * @see CalendarEvent#fetchBody() */ public boolean createIcs(String strUid) { boolean Result = false; TimeZone timezone = null; TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry(); //TODO: do not simply create the ics-file new. take into account the RAWDATA if available /* * dtstart=1365598800000 * dtend=1365602400000 * eventTimezone=Europe/Berlin * eventEndTimezone=null * duration=null * allDay=0 * rrule=null * rdate=null * exrule=null * exdate=null * title=Einurlner Termin * description=null * eventLocation=null * accessLevel=0 * eventStatus=0 * * calendar_id=4 * lastDate=-197200128 * sync_data1=null * _sync_id=null * dirty=1 */ try { mCalendar = new Calendar(); PropertyList propCalendar = mCalendar.getProperties(); propCalendar.add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN")); propCalendar.add(Version.VERSION_2_0); propCalendar.add(CalScale.GREGORIAN); VEvent event = new VEvent(); mCalendar.getComponents().add(event); PropertyList propEvent = event.getProperties(); // DTSTAMP -> is created by new VEvent() automatical //na // CREATED //na // LAST-MODIFIED //na // SEQUENCE //na // DTSTART long lngStart = this.ContentValues.getAsLong(Events.DTSTART); String strTZStart = this.ContentValues.getAsString(Events.EVENT_TIMEZONE); boolean allDay = this.ContentValues.getAsBoolean(Events.ALL_DAY); if (lngStart > 0) { DtStart dtStart = new DtStart(); if (allDay) { Date dateStart = new Date(); dateStart.setTime(lngStart); dtStart.setDate(dateStart); } else { DateTime datetimeStart = new DateTime(); datetimeStart.setTime(lngStart); dtStart.setDate(datetimeStart); timezone = registry.getTimeZone(strTZStart); dtStart.setTimeZone(timezone); // no timezone information for allDay events mCalendar.getComponents().add(timezone.getVTimeZone()); } propEvent.add(dtStart); } // DTEND long lngEnd = this.ContentValues.getAsLong(Events.DTEND); String strTZEnd = this.ContentValues.getAsString(Events.EVENT_END_TIMEZONE); if (strTZEnd == null) strTZEnd = strTZStart; if (lngEnd > 0) { DtEnd dtEnd = new DtEnd(); if (allDay) { Date dateEnd = new Date(); dateEnd.setTime(lngEnd); dtEnd.setDate(dateEnd); } else { DateTime datetimeEnd = new DateTime(); datetimeEnd.setTime(lngEnd); dtEnd.setDate(datetimeEnd); if (strTZEnd != null) timezone = registry.getTimeZone(strTZEnd); dtEnd.setTimeZone(timezone); } propEvent.add(dtEnd); } // DURATION if (this.ContentValues.containsKey(Events.DURATION)) { String strDuration = this.ContentValues.getAsString(Events.DURATION); if (strDuration != null) { Duration duration = new Duration(); duration.setValue(strDuration); propEvent.add(duration); } } //RRULE if (this.ContentValues.containsKey(Events.RRULE)) { String strRrule = this.ContentValues.getAsString(Events.RRULE); if (strRrule != null) { if (!strRrule.equals("")) { RRule rrule = new RRule(); rrule.setValue(strRrule); propEvent.add(rrule); } } } //RDATE if (this.ContentValues.containsKey(Events.RDATE)) { String strRdate = this.ContentValues.getAsString(Events.RDATE); if (strRdate != null) { if (!strRdate.equals("")) { RDate rdate = new RDate(); rdate.setValue(strRdate); propEvent.add(rdate); } } } //EXRULE if (this.ContentValues.containsKey(Events.EXRULE)) { String strExrule = this.ContentValues.getAsString(Events.EXRULE); if (strExrule != null) { if (!strExrule.equals("")) { ExRule exrule = new ExRule(); exrule.setValue(strExrule); propEvent.add(exrule); } } } //EXDATE if (this.ContentValues.containsKey(Events.EXDATE)) { String strExdate = this.ContentValues.getAsString(Events.EXDATE); if (strExdate != null) { if (!strExdate.equals("")) { ExDate exdate = new ExDate(); exdate.setValue(strExdate); propEvent.add(exdate); } } } //SUMMARY if (this.ContentValues.containsKey(Events.TITLE)) { String strTitle = this.ContentValues.getAsString(Events.TITLE); if (strTitle != null) { Summary summary = new Summary(strTitle); propEvent.add(summary); } } //DESCIPTION if (this.ContentValues.containsKey(Events.DESCRIPTION)) { String strDescription = this.ContentValues.getAsString(Events.DESCRIPTION); if (strDescription != null) { if (!strDescription.equals("")) { Description description = new Description(strDescription); propEvent.add(description); } } } //LOCATION if (this.ContentValues.containsKey(Events.EVENT_LOCATION)) { String strLocation = this.ContentValues.getAsString(Events.EVENT_LOCATION); if (strLocation != null) { if (!strLocation.equals("")) { Location location = new Location(strLocation); propEvent.add(location); } } } //CLASS / ACCESS_LEVEL if (this.ContentValues.containsKey(Events.ACCESS_LEVEL)) { int accessLevel = this.ContentValues.getAsInteger(Events.ACCESS_LEVEL); Clazz clazz = new Clazz(); if (accessLevel == Events.ACCESS_PUBLIC) clazz.setValue(Clazz.PUBLIC.getValue()); else if (accessLevel == Events.ACCESS_PRIVATE) clazz.setValue(Clazz.PRIVATE.getValue()); else if (accessLevel == Events.ACCESS_CONFIDENTIAL) clazz.setValue(Clazz.CONFIDENTIAL.getValue()); else clazz.setValue(Clazz.PUBLIC.getValue()); propEvent.add(clazz); } //STATUS if (this.ContentValues.containsKey(Events.STATUS)) { int intStatus = this.ContentValues.getAsInteger(Events.STATUS); if (intStatus > -1) { Status status = new Status(); if (intStatus == Events.STATUS_CANCELED) status.setValue(Status.VEVENT_CANCELLED.getValue()); else if (intStatus == Events.STATUS_CONFIRMED) status.setValue(Status.VEVENT_CONFIRMED.getValue()); else if (intStatus == Events.STATUS_TENTATIVE) status.setValue(Status.VEVENT_TENTATIVE.getValue()); propEvent.add(status); } } //UID Uid uid = new Uid(strUid); propEvent.add(uid); // Attendees if (mAttendees.size() > 0) { for (Object objProp: mAttendees) { Property prop = (Property) objProp; propEvent.add(prop); } } // Reminders if (mReminders.size() > 0) { for (Object objComp: mReminders) { Component com = (Component) objComp; event.getAlarms().add(com); } } } catch (ParseException e) { e.printStackTrace(); } return Result; } /** * marks the android event as already handled * @return * @see AndroidEvent#cInternalTag * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats) * @throws RemoteException */ /* public boolean tagAndroidEvent() throws RemoteException { ContentValues values = new ContentValues(); values.put(Event.INTERNALTAG, 1); int RowCount = this.mProvider.update(asSyncAdapter(this.getUri(), this.mAccount.name, this.mAccount.type), values, null, null); //Log.e(TAG,"Rows updated: " + RowCount.toString()); return (RowCount == 1); }*/ /* private 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(); }*/ }