Java tutorial
/** * 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.caldav.entities; import java.io.IOException; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URL; import java.net.URLDecoder; import java.text.ParseException; import java.util.ArrayList; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import net.fortuna.ical4j.data.CalendarBuilder; import net.fortuna.ical4j.data.ParserException; import net.fortuna.ical4j.model.Calendar; import net.fortuna.ical4j.model.Component; import net.fortuna.ical4j.model.ComponentList; 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.Property; import net.fortuna.ical4j.model.PropertyList; import net.fortuna.ical4j.model.TimeZone; import net.fortuna.ical4j.model.component.VEvent; import net.fortuna.ical4j.model.component.VTimeZone; import net.fortuna.ical4j.model.parameter.Cn; import net.fortuna.ical4j.model.parameter.CuType; import net.fortuna.ical4j.model.parameter.PartStat; import net.fortuna.ical4j.model.parameter.Role; import net.fortuna.ical4j.model.property.Clazz; import net.fortuna.ical4j.model.property.Status; import net.fortuna.ical4j.util.CompatibilityHints; import org.apache.http.client.ClientProtocolException; import org.gege.caldavsyncadapter.Event; import org.gege.caldavsyncadapter.android.entities.AndroidEvent; import org.gege.caldavsyncadapter.caldav.CaldavFacade; import org.gege.caldavsyncadapter.caldav.CaldavProtocolException; import org.gege.caldavsyncadapter.caldav.xml.MultiStatusHandler; import org.gege.caldavsyncadapter.caldav.xml.sax.MultiStatus; import org.gege.caldavsyncadapter.caldav.xml.sax.Prop; import org.gege.caldavsyncadapter.caldav.xml.sax.PropStat; import org.gege.caldavsyncadapter.caldav.xml.sax.Response; import org.gege.caldavsyncadapter.syncadapter.SyncAdapter; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import android.accounts.Account; import android.content.ContentProviderClient; import android.content.ContentUris; 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 android.util.Log; public class CalendarEvent extends org.gege.caldavsyncadapter.Event { private static final String TAG = "CalendarEvent"; private String stringIcs; private Calendar calendar; private Component calendarComponent; private String eTag; private URI muri; private Uri mAndroidEventUri; public URL calendarURL; private boolean mAllDay = false; private VTimeZone mVTimeZone = null; private TimeZone mTimeZone = null; private String mstrTimeZoneStart = ""; private String mstrTimeZoneEnd = ""; private Account mAccount = null; private ContentProviderClient mProvider = null; public CalendarEvent(Account account, ContentProviderClient provider) { this.mAccount = account; this.mProvider = provider; } public String getETag() { return eTag; } public void setETag(String eTag) { this.eTag = eTag; } public URI getUri() { return muri; } public void setUri(URI uri) { this.muri = uri; } public void setICSasString(String ics) { this.stringIcs = ics; } public boolean setICSasMultiStatus(String stringMultiStatus) { boolean Result = false; String ics = ""; MultiStatus multistatus; ArrayList<Response> responselist; Response response; PropStat propstat; Prop prop; try { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); XMLReader reader = parser.getXMLReader(); MultiStatusHandler contentHandler = new MultiStatusHandler(); reader.setContentHandler(contentHandler); reader.parse(new InputSource(new StringReader(stringMultiStatus))); multistatus = contentHandler.mMultiStatus; if (multistatus != null) { responselist = multistatus.ResponseList; if (responselist.size() == 1) { response = responselist.get(0); //HINT: bugfix for google calendar if (response.href.equals(this.getUri().getPath().replace("@", "%40"))) { propstat = response.propstat; if (propstat.status.contains("200 OK")) { prop = propstat.prop; ics = prop.calendardata; this.setETag(prop.getetag); Result = true; } } } } } catch (ParserConfigurationException e1) { e1.printStackTrace(); } catch (SAXException e1) { e1.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } this.stringIcs = ics; return Result; } /** * sets the Uri of the android event * @param uri * @see org.gege.caldavsyncadapter.syncadapter.SyncAdapter#createAndroidEvent(ContentProviderClient provider, Account account, Uri calendarUri, CalendarEvent calendarEvent) * @see org.gege.caldavsyncadapter.syncadapter.SyncAdapter#updateAndroidEvent(ContentProviderClient provider, Account account, AndroidEvent androidEvent, CalendarEvent calendarEvent) */ public void setAndroidEventUri(Uri uri) { mAndroidEventUri = uri; } /** * gets the Uri of the android event * @return */ public Uri getAndroidEventUri() { return mAndroidEventUri; } /** * reads all ContentValues from the caldav source * @param calendarUri * @return * @see org.gege.caldavsyncadapter.syncadapter.SyncAdapter#createAndroidEvent(ContentProviderClient provider, Account account, Uri calendarUri, CalendarEvent calendarEvent) * @see org.gege.caldavsyncadapter.syncadapter.SyncAdapter#updateAndroidEvent(ContentProviderClient provider, Account account, AndroidEvent androidEvent, CalendarEvent calendarEvent) */ public boolean readContentValues() { this.ContentValues.put(Events.DTSTART, this.getStartTime()); this.ContentValues.put(Events.EVENT_TIMEZONE, this.getTimeZoneStart()); //if (this.getRRule().isEmpty() && this.getRDate().isEmpty()) { if (this.getRRule() == null && this.getRDate() == null) { //if (AllDay.equals(1)) //{ // values.put(Events.ALL_DAY, AllDay); //} else { this.ContentValues.put(Events.DTEND, this.getEndTime()); this.ContentValues.put(Events.EVENT_END_TIMEZONE, this.getTimeZoneEnd()); //} } else { //if (AllDay.equals(1)) // values.put(Events.ALL_DAY, AllDay); this.ContentValues.put(Events.DURATION, this.getDuration()); } int AllDay = this.getAllDay(); this.ContentValues.put(Events.ALL_DAY, AllDay); this.ContentValues.put(Events.TITLE, this.getTitle()); //this.ContentValues.put(Events.CALENDAR_ID, ContentUris.parseId(calendarUri)); this.ContentValues.put(Events._SYNC_ID, this.getUri().toString()); this.ContentValues.put(ETAG, this.getETag()); this.ContentValues.put(Events.DESCRIPTION, this.getDescription()); this.ContentValues.put(Events.EVENT_LOCATION, this.getLocation()); this.ContentValues.put(Events.ACCESS_LEVEL, this.getAccessLevel()); this.ContentValues.put(Events.STATUS, this.getStatus()); this.ContentValues.put(Events.RDATE, this.getRDate()); this.ContentValues.put(Events.RRULE, this.getRRule()); this.ContentValues.put(Events.EXRULE, this.getExRule()); this.ContentValues.put(Events.EXDATE, this.getExDate()); this.ContentValues.put(UID, this.getUid()); this.ContentValues.put(RAWDATA, this.stringIcs); return true; } /** * receives a single event and parses its content * @return success of this function * @see CalendarEvent#parseIcs() * @throws ClientProtocolException * @throws IOException * @throws CaldavProtocolException * @throws ParserException */ public boolean fetchBody() throws ClientProtocolException, IOException, CaldavProtocolException, ParserException { boolean Error = false; //replaced fetchEvent() with getEvent() //CaldavFacade.fetchEvent(this); CaldavFacade.getEvent(this); boolean Parse = this.parseIcs(); if (!Parse) Error = true; return !Error; } public java.util.ArrayList<ContentValues> getReminders() { java.util.ArrayList<ContentValues> Result = new java.util.ArrayList<ContentValues>(); ContentValues Reminder; /* * http://sourceforge.net/tracker/?func=detail&aid=3021704&group_id=107024&atid=646395 */ net.fortuna.ical4j.model.component.VEvent event = (VEvent) this.calendarComponent; //ComponentList ComList = this.calendar.getComponents(Component.VALARM); ComponentList ComList = event.getAlarms(); if (ComList != null) { for (Object objCom : ComList) { Component Com = (Component) objCom; Reminder = new ContentValues(); //Property ACTION = Com.getProperty("ACTION"); Property TRIGGER = Com.getProperty("TRIGGER"); if (TRIGGER != null) { Dur Duration = new Dur(TRIGGER.getValue()); //if (ACTION.getValue().equals("DISPLAY")) int intDuration = Duration.getMinutes() + Duration.getHours() * 60 + Duration.getDays() * 60 * 24; Reminder.put(Reminders.EVENT_ID, ContentUris.parseId(mAndroidEventUri)); Reminder.put(Reminders.METHOD, Reminders.METHOD_ALERT); Reminder.put(Reminders.MINUTES, intDuration); Result.add(Reminder); } } } return Result; } public java.util.ArrayList<ContentValues> getAttandees() { java.util.ArrayList<ContentValues> Result = new java.util.ArrayList<ContentValues>(); ContentValues Attendee; PropertyList Propertys = calendarComponent.getProperties(Property.ATTENDEE); if (Propertys != null) { for (Object objProperty : Propertys) { Property property = (Property) objProperty; Attendee = ReadAttendeeProperties(property, Property.ATTENDEE); if (Attendee != null) Result.add(Attendee); } } Propertys = calendarComponent.getProperties(Property.ORGANIZER); if (Propertys != null) { for (Object objProperty : Propertys) { Property property = (Property) objProperty; Attendee = ReadAttendeeProperties(property, Property.ORGANIZER); if (Attendee != null) Result.add(Attendee); } } return Result; } private String mstrcIcalPropertyError = "net.fortunal.ical4j.invalid:"; private ContentValues ReadAttendeeProperties(Property property, String Type) { ContentValues Attendee = null; ParameterList Parameters = property.getParameters(); Parameter CN = Parameters.getParameter(Cn.CN); Parameter ROLE = Parameters.getParameter(Role.ROLE); Parameter CUTYPE = Parameters.getParameter(CuType.CUTYPE); //Parameter RSVP = Parameters.getParameter("RSVP"); Parameter PARTSTAT = Parameters.getParameter(PartStat.PARTSTAT); String strCN = ""; String strROLE = ""; String strCUTYPE = ""; String strValue = property.getValue().replace("mailto:", ""); String strPARTSTAT = ""; if (strValue.startsWith(mstrcIcalPropertyError)) { strValue = strValue.replace(mstrcIcalPropertyError, ""); try { strValue = URLDecoder.decode(strValue, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } if (CN != null) strCN = CN.getValue(); if (ROLE != null) strROLE = ROLE.getValue(); if (CUTYPE != null) strCUTYPE = CUTYPE.getValue(); if (PARTSTAT != null) strPARTSTAT = PARTSTAT.getValue(); if (strCN.equals("")) { if (!strValue.equals("")) { strCN = strValue; } } if (!strCN.equals("")) { if (strCUTYPE.equals("") || strCUTYPE.equals("INDIVIDUAL")) { Attendee = new ContentValues(); Attendee.put(Attendees.EVENT_ID, ContentUris.parseId(mAndroidEventUri)); Attendee.put(Attendees.ATTENDEE_NAME, strCN); Attendee.put(Attendees.ATTENDEE_EMAIL, strValue); if (strROLE.equals("OPT-PARTICIPANT")) Attendee.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_OPTIONAL); else if (strROLE.equals("NON-PARTICIPANT")) Attendee.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_NONE); else if (strROLE.equals("REQ-PARTICIPANT")) Attendee.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED); else if (strROLE.equals("CHAIR")) Attendee.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED); else Attendee.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_NONE); if (Type.equals(Property.ATTENDEE)) Attendee.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE); else if (Type.equals(Property.ORGANIZER)) Attendee.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ORGANIZER); else Attendee.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_NONE); if (strPARTSTAT.equals(PartStat.NEEDS_ACTION.getValue())) Attendee.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_INVITED); else if (strPARTSTAT.equals(PartStat.ACCEPTED.getValue())) Attendee.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_ACCEPTED); else if (strPARTSTAT.equals(PartStat.DECLINED.getValue())) Attendee.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_DECLINED); else if (strPARTSTAT.equals(PartStat.COMPLETED.getValue())) Attendee.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_NONE); else if (strPARTSTAT.equals(PartStat.TENTATIVE.getValue())) Attendee.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_TENTATIVE); else Attendee.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_INVITED); } } return Attendee; } private long getAccessLevel() { long Result = Events.ACCESS_DEFAULT; String Value = ""; Property property = calendarComponent.getProperty(Property.CLASS); if (property != null) { Value = property.getValue(); if (Value.equals(Clazz.PUBLIC)) Result = Events.ACCESS_PUBLIC; else if (Value.equals(Clazz.PRIVATE)) Result = Events.ACCESS_PRIVATE; else if (Value.equals(Clazz.CONFIDENTIAL)) Result = Events.ACCESS_PRIVATE; // should be ACCESS_CONFIDENTIAL, but is not implemented within Android } return Result; } private int getStatus() { int Result = -1; String Value = ""; Property property = calendarComponent.getProperty(Property.STATUS); if (property != null) { Value = property.getValue(); if (Value.equals(Status.VEVENT_CONFIRMED.getValue())) Result = Events.STATUS_CONFIRMED; else if (Value.equals(Status.VEVENT_CANCELLED.getValue())) Result = Events.STATUS_CANCELED; else if (Value.equals(Status.VEVENT_TENTATIVE.getValue())) Result = Events.STATUS_TENTATIVE; } return Result; } private String getDescription() { String Result = null; Property property = calendarComponent.getProperty(Property.DESCRIPTION); if (property != null) Result = property.getValue(); return Result; } private String getLocation() { String Result = null; Property property = calendarComponent.getProperty(Property.LOCATION); if (property != null) Result = property.getValue(); return Result; } private String getTitle() { Property property = calendarComponent.getProperty(Property.SUMMARY); if (property != null) return property.getValue(); else return "**unkonwn**"; } private String getRRule() { String Result = null; Property property = calendarComponent.getProperty(Property.RRULE); if (property != null) Result = property.getValue(); return Result; } private String getExRule() { String Result = null; Property property = calendarComponent.getProperty(Property.EXRULE); if (property != null) Result = property.getValue(); return Result; } private String getRDate() { String Result = null; java.util.ArrayList<String> ExDates = this.getRDates(); for (String Value : ExDates) { if (Result == null) Result = ""; if (!Result.isEmpty()) Result += ","; Result += Value; } return Result; } private java.util.ArrayList<String> getRDates() { java.util.ArrayList<String> Result = new java.util.ArrayList<String>(); PropertyList Propertys = calendarComponent.getProperties(Property.RDATE); if (Propertys != null) { Property property; for (Object objProperty : Propertys) { property = (Property) objProperty; Result.add(property.getValue()); } } return Result; } private String getExDate() { String Result = null; java.util.ArrayList<String> ExDates = this.getExDates(); for (String Value : ExDates) { if (Result == null) Result = ""; if (!Result.isEmpty()) Result += ","; Result += Value; } return Result; } private java.util.ArrayList<String> getExDates() { java.util.ArrayList<String> Result = new java.util.ArrayList<String>(); PropertyList Propertys = calendarComponent.getProperties(Property.EXDATE); if (Propertys != null) { Property property; for (Object objProperty : Propertys) { property = (Property) objProperty; Result.add(property.getValue()); } } return Result; } private String getUid() { String Result = ""; Property prop = calendarComponent.getProperty(Property.UID); if (prop != null) { Result = prop.getValue(); } return Result; } private Long getTimestamp(Property prop) { Long Result = null; String strTimeZone = ""; //TimeZone timeZone = null; try { String strDate = prop.getValue(); Parameter parAllDay = prop.getParameter("VALUE"); if (parAllDay != null) { if (parAllDay.getValue().equals("DATE")) { mAllDay = true; strDate += "T000000Z"; } } Parameter propTZ = prop.getParameter(Property.TZID); if (propTZ != null) strTimeZone = propTZ.getValue(); //TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry(); //if (!strTimeZone.equals("")) // timeZone = registry.getTimeZone(strTimeZone); //if (timeZone != null) { if (!strTimeZone.equals("")) { //Result = new DateTime(strDate, timeZone); //Result1 = Result.getTime(); //20130331T120000 int Year = Integer.parseInt(strDate.substring(0, 4)); int Month = Integer.parseInt(strDate.substring(4, 6)) - 1; int Day = Integer.parseInt(strDate.substring(6, 8)); int Hour = Integer.parseInt(strDate.substring(9, 11)); int Minute = Integer.parseInt(strDate.substring(11, 13)); int Second = Integer.parseInt(strDate.substring(13, 15)); // time in UTC java.util.TimeZone jtz = java.util.TimeZone.getTimeZone("UTC"); java.util.Calendar cal = java.util.GregorianCalendar.getInstance(jtz); cal.set(Year, Month, Day, Hour, Minute, Second); cal.set(java.util.Calendar.MILLISECOND, 0); Result = cal.getTimeInMillis(); // get the timezone String[] IDs = java.util.TimeZone.getAvailableIDs(); Boolean Found = false; for (int i = 0; i < IDs.length; i++) { Found = Found || IDs[i].equals(strTimeZone); } if (Found) { jtz = java.util.TimeZone.getTimeZone(strTimeZone); // subtract the offset Result -= jtz.getRawOffset(); // remove dst if (jtz.inDaylightTime(new java.util.Date(Result))) Result -= jtz.getDSTSavings(); } else { if (mTimeZone != null) { // subtract the offset Result -= mTimeZone.getRawOffset(); // remove dst if (mTimeZone.inDaylightTime(new java.util.Date(Result))) Result -= mTimeZone.getDSTSavings(); } else { // unknown Time? // treat as local time, should not happen too often :) Result = new DateTime(strDate).getTime(); } } } else { if (strDate.endsWith("Z")) { // GMT or UTC Result = new DateTime(strDate).getTime(); } else { // unknown Time? // treat as local time, should not happen too often :) Result = new DateTime(strDate).getTime(); } } } catch (ParseException e) { e.printStackTrace(); } return Result; } private long getStartTime() { long Result = 0; Property prop; /* * DTSTART;TZID=Europe/Berlin:20120425T080000 * DTSTART;TZID=(GMT+01.00) Sarajevo/Warsaw/Zagreb:20120305T104500 * DTSTART:20120308T093000Z * DTSTART;VALUE=DATE:20120709 * DTSTART;TZID=Europe/Berlin:20130330T100000 */ prop = calendarComponent.getProperty(Property.DTSTART); if (prop != null) { Parameter propTZ = prop.getParameter(Property.TZID); if (propTZ != null) mstrTimeZoneStart = propTZ.getValue(); Result = getTimestamp(prop); } return Result; } private long getEndTime() { long Result = 0; Property propDtEnd; Property propDuration; propDtEnd = calendarComponent.getProperty(Property.DTEND); propDuration = calendarComponent.getProperty(Property.DURATION); if (propDtEnd != null) { Parameter propTZ = propDtEnd.getParameter(Property.TZID); if (propTZ != null) mstrTimeZoneEnd = propTZ.getValue(); Result = getTimestamp(propDtEnd); } else if (propDuration != null) { Result = 0; long Start = this.getStartTime(); String strDuration = propDuration.getValue(); Dur dur = new Dur(strDuration); Result = Start + dur.getSeconds() * 1000 + dur.getMinutes() * 60 * 1000 + dur.getHours() * 60 * 60 * 1000 + dur.getDays() * 60 * 60 * 24 * 1000; mstrTimeZoneEnd = mstrTimeZoneStart; } return Result; } private String getTimeZoneStart() { String Result = "GMT"; if (!mstrTimeZoneStart.equals("")) { Result = mstrTimeZoneStart; } return Result; } private String getTimeZoneEnd() { String Result = "GMT"; if (!mstrTimeZoneEnd.equals("")) { Result = mstrTimeZoneEnd; } return Result; } private String getDuration() { String Result = ""; Property prop = calendarComponent.getProperty("DURATION"); if (prop != null) { //DURATION:PT1H Result = prop.getValue(); } else { // no DURATION given by this event. we have to calculate it by ourself Result = "P"; long Start = this.getStartTime(); long End = this.getEndTime(); long Duration = 0; if (End != 0) Duration = (End - Start) / 1000; // get rid of the milliseconds, they cann't be described with RFC2445-Duration int Days = (int) Math.ceil(Duration / 24 / 60 / 60); int Hours = (int) Math.ceil((Duration - (Days * 24 * 60 * 60)) / 60 / 60); int Minutes = (int) Math.ceil((Duration - (Days * 24 * 60 * 60) - (Hours * 60 * 60)) / 60); int Seconds = (int) (Duration - (Days * 24 * 60 * 60) - (Hours * 60 * 60) - (Minutes * 60)); if (Days > 0) Result += String.valueOf(Days) + "D"; if (!mAllDay) { //if a ALL_DAY event occurs, there is no need for hours, minutes and seconds (Android doesn't understand them) Result += "T"; Result += String.valueOf(Hours) + "H"; Result += String.valueOf(Minutes) + "M"; Result += String.valueOf(Seconds) + "S"; } } return Result; } private int getAllDay() { int Result = 0; if (mAllDay) Result = 1; return Result; } /** * opens the first items of the event * @return success of this function * @see AndroidEvent#createIcs() * @see CalendarEvent#fetchBody() * @throws CaldavProtocolException * @throws IOException * @throws ParserException */ private boolean parseIcs() throws CaldavProtocolException, IOException, ParserException { boolean Error = false; CalendarBuilder builder = new CalendarBuilder(); CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_UNFOLDING, true); CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING, true); CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION, true); CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_OUTLOOK_COMPATIBILITY, true); StringReader reader = new StringReader(this.stringIcs); try { this.calendar = builder.build(reader); } catch (ParserException ex) { // ical4j fails with this: "Cannot set timezone for UTC properties" // CREATED;TZID=America/New_York:20130129T140250 Error = true; } if (!Error) { ComponentList components = null; components = this.calendar.getComponents(Component.VEVENT); if (components.size() == 0) { components = this.calendar.getComponents(Component.VTODO); if (components.size() == 0) { throw new CaldavProtocolException("unknown events in ICS"); } else { Log.e(TAG, "unsupported event TODO in ICS"); Error = true; } } else if (components.size() > 1) { Log.e(TAG, "Several events in ICS -> only first will be processed"); } // get the TimeZone information Component mCom = this.calendar.getComponent(Component.VTIMEZONE); if (mCom != null) mVTimeZone = (VTimeZone) this.calendar.getComponent(Component.VTIMEZONE); if (mVTimeZone != null) mTimeZone = new TimeZone(mVTimeZone); if (!Error) calendarComponent = (Component) components.get(0); } return !Error; } /** * searches for an android event * @param androidCalendar * @return the android event * @throws RemoteException */ public AndroidEvent getAndroidEvent(DavCalendar androidCalendar) throws RemoteException { boolean Error = false; Uri uriEvents = Events.CONTENT_URI; Uri uriAttendee = Attendees.CONTENT_URI; Uri uriReminder = Reminders.CONTENT_URI; AndroidEvent androidEvent = null; String selection = "(" + Events._SYNC_ID + " = ?)"; String[] selectionArgs = new String[] { this.getUri().toString() }; Cursor curEvent = this.mProvider.query(uriEvents, null, selection, selectionArgs, null); Cursor curAttendee = null; Cursor curReminder = null; if (curEvent == null) { Error = true; } if (!Error) { if (curEvent.getCount() == 0) { Error = true; } } if (!Error) { curEvent.moveToNext(); long EventID = curEvent.getLong(curEvent.getColumnIndex(Events._ID)); Uri returnedUri = ContentUris.withAppendedId(uriEvents, EventID); androidEvent = new AndroidEvent(this.mAccount, this.mProvider, returnedUri, androidCalendar.getAndroidCalendarUri()); androidEvent.readContentValues(curEvent); selection = "(" + Attendees.EVENT_ID + " = ?)"; selectionArgs = new String[] { String.valueOf(EventID) }; curAttendee = this.mProvider.query(uriAttendee, null, selection, selectionArgs, null); selection = "(" + Reminders.EVENT_ID + " = ?)"; selectionArgs = new String[] { String.valueOf(EventID) }; curReminder = this.mProvider.query(uriReminder, null, selection, selectionArgs, null); androidEvent.readAttendees(curAttendee); androidEvent.readReminder(curReminder); curAttendee.close(); curReminder.close(); } curEvent.close(); return androidEvent; } /** * creates a new androidEvent from a given calendarEvent * @param androidCalendar * @return * @throws ClientProtocolException * @throws IOException * @throws CaldavProtocolException * @throws RemoteException * @throws ParserException * @see {@link SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats)} */ public boolean createAndroidEvent(DavCalendar androidCalendar) throws ClientProtocolException, IOException, CaldavProtocolException, RemoteException, ParserException { boolean Result = false; boolean BodyFetched = this.fetchBody(); int CountAttendees = 0; int CountReminders = 0; if (BodyFetched) { //calendarEvent.readContentValues(calendarUri); this.readContentValues(); this.setAndroidCalendarId(ContentUris.parseId(androidCalendar.getAndroidCalendarUri())); Uri uri = this.mProvider.insert( asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), this.ContentValues); this.setAndroidEventUri(uri); Log.d(TAG, "Creating calendar event for " + uri.toString()); //check the attendees java.util.ArrayList<ContentValues> AttendeeList = this.getAttandees(); for (ContentValues Attendee : AttendeeList) { this.mProvider.insert(Attendees.CONTENT_URI, Attendee); CountAttendees += 1; } //check the reminders java.util.ArrayList<ContentValues> ReminderList = this.getReminders(); for (ContentValues Reminder : ReminderList) { this.mProvider.insert(Reminders.CONTENT_URI, Reminder); CountReminders += 1; } if ((CountAttendees > 0) || (CountReminders > 0)) { //the events gets dirty when attendees or reminders were added AndroidEvent androidEvent = this.getAndroidEvent(androidCalendar); androidEvent.ContentValues.put(Events.DIRTY, 0); int RowCount = this.mProvider.update( asSyncAdapter(androidEvent.getUri(), this.mAccount.name, this.mAccount.type), androidEvent.ContentValues, null, null); Result = (RowCount == 1); } else { Result = true; } } return Result; } /** * the android event is getting updated * @param provider * @param account * @param androidEvent * @param calendarEvent * @return * @throws ClientProtocolException * @throws IOException * @throws CaldavProtocolException * @throws RemoteException * @throws ParserException * @see {@link SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, Calendar, SyncStats)} */ public boolean updateAndroidEvent(AndroidEvent androidEvent) throws ClientProtocolException, IOException, CaldavProtocolException, RemoteException, ParserException { boolean BodyFetched = this.fetchBody(); int Rows = 0; if (BodyFetched) { this.readContentValues(); this.setAndroidCalendarId(androidEvent.getAndroidCalendarId()); this.setAndroidEventUri(androidEvent.getUri()); Log.d(TAG, "AndroidEvent is dirty: " + androidEvent.ContentValues.getAsString(Events.DIRTY)); if (androidEvent.checkEventValuesChanged(this.ContentValues)) { // just set the raw data from server event into android event if (androidEvent.ContentValues.containsKey(Event.RAWDATA)) androidEvent.ContentValues.remove(Event.RAWDATA); androidEvent.ContentValues.put(Event.RAWDATA, this.ContentValues.getAsString(Event.RAWDATA)); //update the attendees and reminders this.updateAndroidAttendees(); this.updateAndroidReminder(); androidEvent.ContentValues.put(Events.DIRTY, 0); // the event is now in sync Log.d(TAG, "Update calendar event: for " + androidEvent.getUri()); Rows = mProvider.update(asSyncAdapter(androidEvent.getUri(), mAccount.name, mAccount.type), androidEvent.ContentValues, null, null); //Log.i(TAG, "Updated calendar event: rows effected " + Rows.toString()); } else { Log.d(TAG, "Update calendar event not needed: for " + androidEvent.getUri()); } } return (Rows == 1); } /** * updates the attendees from a calendarEvent to its androidEvent. * the calendarEvent has to know its androidEvent via {@link CalendarEvent#setAndroidEventUri(Uri)} * @param provider * @return * @see SyncAdapter#updateAndroidEvent(ContentProviderClient, Account, AndroidEvent, CalendarEvent) */ private boolean updateAndroidAttendees() { boolean Result = false; try { String mSelectionClause = "(" + Attendees.EVENT_ID + " = ?)"; String[] mSelectionArgs = { Long.toString(ContentUris.parseId(this.getAndroidEventUri())) }; int RowDelete; RowDelete = this.mProvider.delete(Attendees.CONTENT_URI, mSelectionClause, mSelectionArgs); Log.d(TAG, "Attendees Deleted:" + String.valueOf(RowDelete)); java.util.ArrayList<ContentValues> AttendeeList = this.getAttandees(); for (ContentValues Attendee : AttendeeList) { this.mProvider.insert(Attendees.CONTENT_URI, Attendee); } Log.d(TAG, "Attendees Inserted:" + String.valueOf(AttendeeList.size())); Result = true; } catch (RemoteException e) { e.printStackTrace(); } return Result; } /** * update the reminders from a calendarEvent to its androidEvent. * the calendarEvent has to know its androidEvent via {@link CalendarEvent#setAndroidEventUri(Uri)} * @param provider * @return * @see SyncAdapter#updateAndroidEvent(ContentProviderClient, Account, AndroidEvent, CalendarEvent) */ private boolean updateAndroidReminder() { boolean Result = false; try { String mSelectionClause = "(" + Reminders.EVENT_ID + " = ?)"; String[] mSelectionArgs = { Long.toString(ContentUris.parseId(this.getAndroidEventUri())) }; int RowDelete; RowDelete = this.mProvider.delete(Reminders.CONTENT_URI, mSelectionClause, mSelectionArgs); Log.d(TAG, "Reminders Deleted:" + String.valueOf(RowDelete)); Uri ReminderUri; java.util.ArrayList<ContentValues> ReminderList = this.getReminders(); for (ContentValues Reminder : ReminderList) { ReminderUri = this.mProvider.insert(Reminders.CONTENT_URI, Reminder); System.out.println(ReminderUri); } Log.d(TAG, "Reminders Inserted:" + String.valueOf(ReminderList.size())); Result = true; } catch (RemoteException e) { e.printStackTrace(); } return Result; } 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(); } }