Tue, 10 Feb 2015 22:55:00 +0100
Port to VAlarm class behaviour of upgraded ical4j version 1.0.6.
1 /**
2 * Copyright (c) 2012-2013, Gerald Garcia, Timo Berger
3 *
4 * This file is part of Andoid Caldav Sync Adapter Free.
5 *
6 * Andoid Caldav Sync Adapter Free is free software: you can redistribute
7 * it and/or modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation, either version 3 of the
9 * License, or at your option any later version.
10 *
11 * Andoid Caldav Sync Adapter Free is distributed in the hope that
12 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
13 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Andoid Caldav Sync Adapter Free.
18 * If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
22 package org.gege.caldavsyncadapter.android.entities;
24 import android.database.Cursor;
25 import android.net.Uri;
26 import android.provider.CalendarContract.Attendees;
27 import android.provider.CalendarContract.Events;
28 import android.provider.CalendarContract.Reminders;
30 import net.fortuna.ical4j.model.Calendar;
31 import net.fortuna.ical4j.model.Component;
32 import net.fortuna.ical4j.model.ComponentList;
33 import net.fortuna.ical4j.model.Date;
34 import net.fortuna.ical4j.model.DateTime;
35 import net.fortuna.ical4j.model.Dur;
36 import net.fortuna.ical4j.model.ParameterList;
37 import net.fortuna.ical4j.model.Property;
38 import net.fortuna.ical4j.model.PropertyList;
39 import net.fortuna.ical4j.model.TimeZone;
40 import net.fortuna.ical4j.model.TimeZoneRegistry;
41 import net.fortuna.ical4j.model.TimeZoneRegistryFactory;
42 import net.fortuna.ical4j.model.component.VAlarm;
43 import net.fortuna.ical4j.model.component.VEvent;
44 import net.fortuna.ical4j.model.parameter.Cn;
45 import net.fortuna.ical4j.model.parameter.PartStat;
46 import net.fortuna.ical4j.model.parameter.Role;
47 import net.fortuna.ical4j.model.parameter.Rsvp;
48 import net.fortuna.ical4j.model.parameter.Value;
49 import net.fortuna.ical4j.model.property.Action;
50 import net.fortuna.ical4j.model.property.Attendee;
51 import net.fortuna.ical4j.model.property.CalScale;
52 import net.fortuna.ical4j.model.property.Clazz;
53 import net.fortuna.ical4j.model.property.Description;
54 import net.fortuna.ical4j.model.property.DtEnd;
55 import net.fortuna.ical4j.model.property.DtStart;
56 import net.fortuna.ical4j.model.property.Duration;
57 import net.fortuna.ical4j.model.property.ExDate;
58 import net.fortuna.ical4j.model.property.ExRule;
59 import net.fortuna.ical4j.model.property.Location;
60 import net.fortuna.ical4j.model.property.Organizer;
61 import net.fortuna.ical4j.model.property.ProdId;
62 import net.fortuna.ical4j.model.property.RDate;
63 import net.fortuna.ical4j.model.property.RRule;
64 import net.fortuna.ical4j.model.property.Status;
65 import net.fortuna.ical4j.model.property.Summary;
66 import net.fortuna.ical4j.model.property.Trigger;
67 import net.fortuna.ical4j.model.property.Uid;
68 import net.fortuna.ical4j.model.property.Version;
70 import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent;
72 import java.net.URISyntaxException;
73 import java.text.ParseException;
75 //import android.accounts.Account;
76 //import android.content.ContentProviderClient;
77 //import android.content.ContentValues;
78 //import android.content.SyncStats;
79 //import android.os.RemoteException;
80 //import android.provider.CalendarContract.Calendars;
81 //import org.gege.caldavsyncadapter.Event;
82 //import org.gege.caldavsyncadapter.caldav.CaldavFacade;
83 //import org.gege.caldavsyncadapter.caldav.entities.DavCalendar;
84 //import org.gege.caldavsyncadapter.syncadapter.SyncAdapter;
86 public class AndroidEvent extends org.gege.caldavsyncadapter.Event {
88 private Uri muri;
90 private Uri mAndroidCalendarUri;
92 /**
93 * the list of attendees
94 */
95 private PropertyList mAttendees = new PropertyList();
97 /**
98 * the list of reminders
99 */
100 private ComponentList mReminders = new ComponentList();
102 private Calendar mCalendar = null;
104 /* private Account mAccount = null;
105 private ContentProviderClient mProvider = null;*/
107 //public AndroidEvent(Account account, ContentProviderClient provider, Uri uri, Uri calendarUri) {
108 public AndroidEvent(Uri uri, Uri calendarUri) {
109 super();
110 this.setUri(uri);
111 /* this.mAccount = account;
112 this.mProvider = provider;*/
113 //this.setCounterpartUri(calendarUri);
114 mAndroidCalendarUri = calendarUri;
115 }
117 public Calendar getIcsEvent() {
118 return mCalendar;
119 }
121 public String getETag() {
122 String Result = "";
123 if (this.ContentValues.containsKey(ETAG))
124 Result = this.ContentValues.getAsString(ETAG);
125 return Result;
126 }
128 public void setETag(String eTag) {
129 this.ContentValues.put(ETAG, eTag);
130 }
132 public Uri getUri() {
133 return muri;
134 }
136 public void setUri(Uri uri) {
137 this.muri = uri;
138 }
140 public Uri getAndroidCalendarUri() {
141 return mAndroidCalendarUri;
142 }
144 @Override
145 public String toString() {
146 return this.getUri().toString();
147 }
149 /**
150 * reads an android event from a given cursor into {@link AndroidEvent#ContentValues}
151 *
152 * @param cur the cursor with the event
153 * @return success of this funtion
154 * @see AndroidEvent#ContentValues
155 */
156 public boolean readContentValues(Cursor cur) {
157 this.setETag(cur.getString(cur.getColumnIndex(ETAG)));
159 this.ContentValues.put(Events.EVENT_TIMEZONE, cur.getString(cur.getColumnIndex(Events.EVENT_TIMEZONE)));
160 this.ContentValues.put(Events.EVENT_END_TIMEZONE, cur.getString(cur.getColumnIndex(Events.EVENT_END_TIMEZONE)));
161 this.ContentValues.put(Events.DTSTART, cur.getLong(cur.getColumnIndex(Events.DTSTART)));
162 this.ContentValues.put(Events.DTEND, cur.getLong(cur.getColumnIndex(Events.DTEND)));
163 this.ContentValues.put(Events.ALL_DAY, cur.getLong(cur.getColumnIndex(Events.ALL_DAY)));
164 this.ContentValues.put(Events.TITLE, cur.getString(cur.getColumnIndex(Events.TITLE)));
165 this.ContentValues.put(Events.CALENDAR_ID, cur.getString(cur.getColumnIndex(Events.CALENDAR_ID)));
166 this.ContentValues.put(Events._SYNC_ID, cur.getString(cur.getColumnIndex(Events._SYNC_ID)));
167 //this.ContentValues.put(Events.SYNC_DATA1, cur.getString(cur.getColumnIndex(Events.SYNC_DATA1))); //not needed here, eTag has already been read
168 this.ContentValues.put(Events.DESCRIPTION, cur.getString(cur.getColumnIndex(Events.DESCRIPTION)));
169 this.ContentValues.put(Events.EVENT_LOCATION, cur.getString(cur.getColumnIndex(Events.EVENT_LOCATION)));
170 this.ContentValues.put(Events.ACCESS_LEVEL, cur.getInt(cur.getColumnIndex(Events.ACCESS_LEVEL)));
172 this.ContentValues.put(Events.STATUS, cur.getInt(cur.getColumnIndex(Events.STATUS)));
174 this.ContentValues.put(Events.LAST_DATE, cur.getInt(cur.getColumnIndex(Events.LAST_DATE)));
175 this.ContentValues.put(Events.DURATION, cur.getString(cur.getColumnIndex(Events.DURATION)));
177 this.ContentValues.put(Events.RDATE, cur.getString(cur.getColumnIndex(Events.RDATE)));
178 this.ContentValues.put(Events.RRULE, cur.getString(cur.getColumnIndex(Events.RRULE)));
179 this.ContentValues.put(Events.EXRULE, cur.getString(cur.getColumnIndex(Events.EXRULE)));
180 this.ContentValues.put(Events.EXDATE, cur.getString(cur.getColumnIndex(Events.EXDATE)));
181 this.ContentValues.put(Events.DIRTY, cur.getInt(cur.getColumnIndex(Events.DIRTY)));
182 this.ContentValues.put(UID, cur.getString(cur.getColumnIndex(UID)));
183 this.ContentValues.put(RAWDATA, cur.getString(cur.getColumnIndex(RAWDATA)));
185 return true;
186 }
188 /**
189 * reads the attendees from a given cursor
190 *
191 * @param cur the cursor with the attendees
192 * @return success of this function
193 * @see AndroidEvent#mAttendees
194 */
195 public boolean readAttendees(Cursor cur) {
196 Attendee attendee = null;
197 Organizer organizer = null;
198 ParameterList paraList = null;
200 String Name = "";
201 Cn cn = null;
203 String Email = "";
205 int Relationship = 0;
208 int Status = 0;
209 PartStat partstat = null;
211 int Type = 0;
212 Role role = null;
214 try {
215 while (cur.moveToNext()) {
216 Name = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_NAME));
217 Email = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_EMAIL));
218 Relationship = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_RELATIONSHIP));
219 Type = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_TYPE));
220 Status = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_STATUS));
222 if (Relationship == Attendees.RELATIONSHIP_ORGANIZER) {
223 organizer = new Organizer();
224 organizer.setValue("mailto:" + Email);
225 paraList = organizer.getParameters();
226 mAttendees.add(organizer);
227 } else {
228 attendee = new Attendee();
229 attendee.setValue("mailto:" + Email);
230 paraList = attendee.getParameters();
231 mAttendees.add(attendee);
232 }
234 Rsvp rsvp = new Rsvp(true);
235 paraList.add(rsvp);
237 cn = new Cn(Name);
238 paraList.add(cn);
240 if (Status == Attendees.ATTENDEE_STATUS_INVITED)
241 partstat = new PartStat(PartStat.NEEDS_ACTION.getValue());
242 else if (Status == Attendees.ATTENDEE_STATUS_ACCEPTED)
243 partstat = new PartStat(PartStat.ACCEPTED.getValue());
244 else if (Status == Attendees.ATTENDEE_STATUS_DECLINED)
245 partstat = new PartStat(PartStat.DECLINED.getValue());
246 else if (Status == Attendees.ATTENDEE_STATUS_NONE)
247 partstat = new PartStat(PartStat.COMPLETED.getValue());
248 else if (Status == Attendees.ATTENDEE_STATUS_TENTATIVE)
249 partstat = new PartStat(PartStat.TENTATIVE.getValue());
250 else
251 partstat = new PartStat(PartStat.NEEDS_ACTION.getValue());
252 paraList.add(partstat);
254 if (Type == Attendees.TYPE_OPTIONAL)
255 role = new Role(Role.OPT_PARTICIPANT.getValue());
256 else if (Type == Attendees.TYPE_NONE)
257 role = new Role(Role.NON_PARTICIPANT.getValue()); //regular participants in android are non required?
258 else if (Type == Attendees.TYPE_REQUIRED)
259 role = new Role(Role.REQ_PARTICIPANT.getValue());
260 else
261 role = new Role(Role.NON_PARTICIPANT.getValue());
262 paraList.add(role);
263 }
265 } catch (URISyntaxException e) {
266 e.printStackTrace();
267 }
268 return true;
269 }
271 /**
272 * reads the reminders from a given cursor
273 *
274 * @param cur the cursor with the reminders
275 * @return success of this function
276 */
277 public boolean readReminder(Cursor cur) {
278 int Method;
279 int Minutes;
280 VAlarm reminder;
281 while (cur.moveToNext()) {
282 reminder = new VAlarm();
283 Method = cur.getInt(cur.getColumnIndex(Reminders.METHOD));
284 Minutes = cur.getInt(cur.getColumnIndex(Reminders.MINUTES)) * -1;
287 Dur dur = new Dur(0, 0, Minutes, 0);
288 Trigger tri = new Trigger(dur);
289 Value val = new Value(Duration.DURATION);
290 tri.getParameters().add(val);
291 reminder.getProperties().add(tri);
293 Description desc = new Description();
294 desc.setValue("caldavsyncadapter standard description");
295 reminder.getProperties().add(desc);
298 if (Method == Reminders.METHOD_EMAIL)
299 reminder.getProperties().add(Action.EMAIL);
300 else
301 reminder.getProperties().add(Action.DISPLAY);
303 this.mReminders.add(reminder);
304 }
305 return true;
306 }
308 /**
309 * generates a new ics-file.
310 * uses {@link AndroidEvent#ContentValues} as source.
311 * this should only be used when a new event has been generated within android.
312 *
313 * @param strUid the UID for this event. example: UID:e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter
314 * @return success of the function
315 * @see CalendarEvent#fetchBody()
316 */
317 public boolean createIcs(String strUid) {
318 boolean Result = false;
319 TimeZone timeZone = null;
320 TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
321 //TODO: do not simply create the ics-file new. take into account the RAWDATA if available
322 /*
323 * dtstart=1365598800000
324 * dtend=1365602400000
325 * eventTimezone=Europe/Berlin
326 * eventEndTimezone=null
327 * duration=null
328 * allDay=0
329 * rrule=null
330 * rdate=null
331 * exrule=null
332 * exdate=null
333 * title=Einurlner Termin
334 * description=null
335 * eventLocation=null
336 * accessLevel=0
337 * eventStatus=0
338 *
339 * calendar_id=4
340 * lastDate=-197200128
341 * sync_data1=null
342 * _sync_id=null
343 * dirty=1
344 */
346 try {
347 mCalendar = new Calendar();
348 PropertyList propCalendar = mCalendar.getProperties();
349 propCalendar.add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN"));
350 propCalendar.add(Version.VERSION_2_0);
351 propCalendar.add(CalScale.GREGORIAN);
353 VEvent event = new VEvent();
354 mCalendar.getComponents().add(event);
355 PropertyList propEvent = event.getProperties();
357 // DTSTAMP -> is created by new VEvent() automatical
358 //na
360 // CREATED
361 //na
363 // LAST-MODIFIED
364 //na
366 // SEQUENCE
367 //na
369 // DTSTART
370 long lngStart = this.ContentValues.getAsLong(Events.DTSTART);
371 String strTZStart = this.ContentValues.getAsString(Events.EVENT_TIMEZONE);
372 boolean allDay = this.ContentValues.getAsBoolean(Events.ALL_DAY);
373 if (lngStart > 0) {
374 DtStart dtStart = new DtStart();
375 if (allDay) {
376 Date dateStart = new Date();
377 dateStart.setTime(lngStart);
378 dtStart.setDate(dateStart);
379 } else {
380 DateTime datetimeStart = new DateTime();
381 datetimeStart.setTime(lngStart);
382 dtStart.setDate(datetimeStart);
384 timeZone = registry.getTimeZone(strTZStart);
385 if (timeZone == null) {
386 java.util.TimeZone systemTimeZone = TimeZone.getTimeZone(strTZStart);
387 if (systemTimeZone == null) {
388 systemTimeZone = TimeZone.getDefault();
389 }
390 timeZone = registry.getTimeZone(systemTimeZone.getID());
391 }
392 dtStart.setTimeZone(timeZone);
394 // no timezone information for allDay events
395 mCalendar.getComponents().add(timeZone.getVTimeZone());
396 }
397 propEvent.add(dtStart);
398 }
400 // DTEND
401 long lngEnd = this.ContentValues.getAsLong(Events.DTEND);
402 String strTZEnd = this.ContentValues.getAsString(Events.EVENT_END_TIMEZONE);
403 if (strTZEnd == null)
404 strTZEnd = strTZStart;
405 if (lngEnd > 0) {
406 DtEnd dtEnd = new DtEnd();
407 if (allDay) {
408 Date dateEnd = new Date();
409 dateEnd.setTime(lngEnd);
410 dtEnd.setDate(dateEnd);
411 } else {
412 DateTime datetimeEnd = new DateTime();
413 datetimeEnd.setTime(lngEnd);
414 dtEnd.setDate(datetimeEnd);
415 if (strTZEnd != null)
416 timeZone = registry.getTimeZone(strTZEnd);
417 dtEnd.setTimeZone(timeZone);
418 }
419 propEvent.add(dtEnd);
420 }
422 // DURATION
423 if (this.ContentValues.containsKey(Events.DURATION)) {
424 String strDuration = this.ContentValues.getAsString(Events.DURATION);
425 if (strDuration != null) {
426 Duration duration = new Duration();
427 duration.setValue(strDuration);
429 propEvent.add(duration);
430 }
431 }
433 //RRULE
434 if (this.ContentValues.containsKey(Events.RRULE)) {
435 String strRrule = this.ContentValues.getAsString(Events.RRULE);
436 if (strRrule != null) {
437 if (!strRrule.equals("")) {
438 RRule rrule = new RRule();
439 rrule.setValue(strRrule);
440 propEvent.add(rrule);
441 }
442 }
443 }
445 //RDATE
446 if (this.ContentValues.containsKey(Events.RDATE)) {
447 String strRdate = this.ContentValues.getAsString(Events.RDATE);
448 if (strRdate != null) {
449 if (!strRdate.equals("")) {
450 RDate rdate = new RDate();
451 rdate.setValue(strRdate);
452 propEvent.add(rdate);
453 }
454 }
455 }
457 //EXRULE
458 if (this.ContentValues.containsKey(Events.EXRULE)) {
459 String strExrule = this.ContentValues.getAsString(Events.EXRULE);
460 if (strExrule != null) {
461 if (!strExrule.equals("")) {
462 ExRule exrule = new ExRule();
463 exrule.setValue(strExrule);
464 propEvent.add(exrule);
465 }
466 }
467 }
469 //EXDATE
470 if (this.ContentValues.containsKey(Events.EXDATE)) {
471 String strExdate = this.ContentValues.getAsString(Events.EXDATE);
472 if (strExdate != null) {
473 if (!strExdate.equals("")) {
474 ExDate exdate = new ExDate();
475 exdate.setValue(strExdate);
476 propEvent.add(exdate);
477 }
478 }
479 }
481 //SUMMARY
482 if (this.ContentValues.containsKey(Events.TITLE)) {
483 String strTitle = this.ContentValues.getAsString(Events.TITLE);
484 if (strTitle != null) {
485 Summary summary = new Summary(strTitle);
486 propEvent.add(summary);
487 }
488 }
490 //DESCIPTION
491 if (this.ContentValues.containsKey(Events.DESCRIPTION)) {
492 String strDescription = this.ContentValues.getAsString(Events.DESCRIPTION);
493 if (strDescription != null) {
494 if (!strDescription.equals("")) {
495 Description description = new Description(strDescription);
496 propEvent.add(description);
497 }
498 }
499 }
501 //LOCATION
502 if (this.ContentValues.containsKey(Events.EVENT_LOCATION)) {
503 String strLocation = this.ContentValues.getAsString(Events.EVENT_LOCATION);
504 if (strLocation != null) {
505 if (!strLocation.equals("")) {
506 Location location = new Location(strLocation);
507 propEvent.add(location);
508 }
509 }
510 }
512 //CLASS / ACCESS_LEVEL
513 if (this.ContentValues.containsKey(Events.ACCESS_LEVEL)) {
514 int accessLevel = this.ContentValues.getAsInteger(Events.ACCESS_LEVEL);
515 Clazz clazz = new Clazz();
516 if (accessLevel == Events.ACCESS_PUBLIC)
517 clazz.setValue(Clazz.PUBLIC.getValue());
518 else if (accessLevel == Events.ACCESS_PRIVATE)
519 clazz.setValue(Clazz.PRIVATE.getValue());
520 else if (accessLevel == Events.ACCESS_CONFIDENTIAL)
521 clazz.setValue(Clazz.CONFIDENTIAL.getValue());
522 else
523 clazz.setValue(Clazz.PUBLIC.getValue());
525 propEvent.add(clazz);
526 }
528 //STATUS
529 if (this.ContentValues.containsKey(Events.STATUS)) {
530 int intStatus = this.ContentValues.getAsInteger(Events.STATUS);
531 if (intStatus > -1) {
532 Status status = new Status();
533 if (intStatus == Events.STATUS_CANCELED)
534 status.setValue(Status.VEVENT_CANCELLED.getValue());
535 else if (intStatus == Events.STATUS_CONFIRMED)
536 status.setValue(Status.VEVENT_CONFIRMED.getValue());
537 else if (intStatus == Events.STATUS_TENTATIVE)
538 status.setValue(Status.VEVENT_TENTATIVE.getValue());
540 propEvent.add(status);
541 }
542 }
544 //UID
545 Uid uid = new Uid(strUid);
546 propEvent.add(uid);
548 // Attendees
549 if (mAttendees.size() > 0) {
550 for (Object objProp : mAttendees) {
551 Property prop = (Property) objProp;
552 propEvent.add(prop);
553 }
554 }
556 // Reminders
557 if (mReminders.size() > 0) {
558 for (Object objComp : mReminders) {
559 VAlarm com = (VAlarm) objComp;
560 event.getAlarms().add(com);
561 }
562 }
564 } catch (ParseException e) {
565 e.printStackTrace();
566 }
568 return Result;
569 }
571 /**
572 * marks the android event as already handled
573 * @return
574 * @see AndroidEvent#cInternalTag
575 * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats)
576 * @throws RemoteException
577 */
578 /* public boolean tagAndroidEvent() throws RemoteException {
580 ContentValues values = new ContentValues();
581 values.put(Event.INTERNALTAG, 1);
583 int RowCount = this.mProvider.update(asSyncAdapter(this.getUri(), this.mAccount.name, this.mAccount.type), values, null, null);
584 //Log.e(TAG,"Rows updated: " + RowCount.toString());
586 return (RowCount == 1);
587 }*/
589 /* private static Uri asSyncAdapter(Uri uri, String account, String accountType) {
590 return uri.buildUpon()
591 .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true")
592 .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
593 .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
594 }*/
595 }