Tue, 10 Feb 2015 18:12:00 +0100
Import initial revisions of existing project AndroidCaldavSyncAdapater,
forked from upstream repository at 27e8a0f8495c92e0780d450bdf0c7cec77a03a55.
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 java.net.URISyntaxException;
25 import java.text.ParseException;
26 import net.fortuna.ical4j.model.Calendar;
27 import net.fortuna.ical4j.model.Component;
28 import net.fortuna.ical4j.model.ComponentList;
29 import net.fortuna.ical4j.model.Date;
30 import net.fortuna.ical4j.model.DateTime;
31 import net.fortuna.ical4j.model.Dur;
32 import net.fortuna.ical4j.model.ParameterList;
33 import net.fortuna.ical4j.model.Property;
34 import net.fortuna.ical4j.model.PropertyList;
35 import net.fortuna.ical4j.model.TimeZone;
36 import net.fortuna.ical4j.model.TimeZoneRegistry;
37 import net.fortuna.ical4j.model.TimeZoneRegistryFactory;
38 import net.fortuna.ical4j.model.component.VAlarm;
39 import net.fortuna.ical4j.model.component.VEvent;
40 import net.fortuna.ical4j.model.parameter.Cn;
41 import net.fortuna.ical4j.model.parameter.PartStat;
42 import net.fortuna.ical4j.model.parameter.Role;
43 import net.fortuna.ical4j.model.parameter.Rsvp;
44 import net.fortuna.ical4j.model.parameter.Value;
45 import net.fortuna.ical4j.model.property.Action;
46 import net.fortuna.ical4j.model.property.Attendee;
47 import net.fortuna.ical4j.model.property.CalScale;
48 import net.fortuna.ical4j.model.property.Clazz;
49 import net.fortuna.ical4j.model.property.Description;
50 import net.fortuna.ical4j.model.property.DtEnd;
51 import net.fortuna.ical4j.model.property.DtStart;
52 import net.fortuna.ical4j.model.property.Duration;
53 import net.fortuna.ical4j.model.property.ExDate;
54 import net.fortuna.ical4j.model.property.ExRule;
55 import net.fortuna.ical4j.model.property.Location;
56 import net.fortuna.ical4j.model.property.Organizer;
57 import net.fortuna.ical4j.model.property.ProdId;
58 import net.fortuna.ical4j.model.property.RDate;
59 import net.fortuna.ical4j.model.property.RRule;
60 import net.fortuna.ical4j.model.property.Status;
61 import net.fortuna.ical4j.model.property.Summary;
62 import net.fortuna.ical4j.model.property.Trigger;
63 import net.fortuna.ical4j.model.property.Uid;
64 import net.fortuna.ical4j.model.property.Version;
65 //import android.accounts.Account;
66 //import android.content.ContentProviderClient;
67 //import android.content.ContentValues;
68 //import android.content.SyncStats;
69 import android.database.Cursor;
70 import android.net.Uri;
71 //import android.os.RemoteException;
72 import android.provider.CalendarContract.Attendees;
73 //import android.provider.CalendarContract.Calendars;
74 import android.provider.CalendarContract.Events;
75 import android.provider.CalendarContract.Reminders;
77 //import org.gege.caldavsyncadapter.Event;
78 //import org.gege.caldavsyncadapter.caldav.CaldavFacade;
79 import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent;
80 //import org.gege.caldavsyncadapter.caldav.entities.DavCalendar;
81 //import org.gege.caldavsyncadapter.syncadapter.SyncAdapter;
83 public class AndroidEvent extends org.gege.caldavsyncadapter.Event {
85 private Uri muri;
87 private Uri mAndroidCalendarUri;
89 /**
90 * the list of attendees
91 */
92 private PropertyList mAttendees = new PropertyList();
94 /**
95 * the list of reminders
96 */
97 private ComponentList mReminders = new ComponentList();
99 private Calendar mCalendar = null;
101 /* private Account mAccount = null;
102 private ContentProviderClient mProvider = null;*/
104 //public AndroidEvent(Account account, ContentProviderClient provider, Uri uri, Uri calendarUri) {
105 public AndroidEvent(Uri uri, Uri calendarUri) {
106 super();
107 this.setUri(uri);
108 /* this.mAccount = account;
109 this.mProvider = provider;*/
110 //this.setCounterpartUri(calendarUri);
111 mAndroidCalendarUri = calendarUri;
112 }
114 public Calendar getIcsEvent() {
115 return mCalendar;
116 }
118 public String getETag() {
119 String Result = "";
120 if (this.ContentValues.containsKey(ETAG))
121 Result = this.ContentValues.getAsString(ETAG);
122 return Result;
123 }
125 public void setETag(String eTag) {
126 this.ContentValues.put(ETAG, eTag);
127 }
129 public Uri getUri() {
130 return muri;
131 }
133 public void setUri(Uri uri) {
134 this.muri = uri;
135 }
137 public Uri getAndroidCalendarUri() {
138 return mAndroidCalendarUri;
139 }
141 @Override
142 public String toString() {
143 return this.getUri().toString();
144 }
146 /**
147 * reads an android event from a given cursor into {@link AndroidEvent#ContentValues}
148 * @param cur the cursor with the event
149 * @return success of this funtion
150 * @see AndroidEvent#ContentValues
151 */
152 public boolean readContentValues(Cursor cur) {
153 this.setETag(cur.getString(cur.getColumnIndex(ETAG)));
155 this.ContentValues.put(Events.EVENT_TIMEZONE, cur.getString(cur.getColumnIndex(Events.EVENT_TIMEZONE)));
156 this.ContentValues.put(Events.EVENT_END_TIMEZONE, cur.getString(cur.getColumnIndex(Events.EVENT_END_TIMEZONE)));
157 this.ContentValues.put(Events.DTSTART, cur.getLong(cur.getColumnIndex(Events.DTSTART)));
158 this.ContentValues.put(Events.DTEND, cur.getLong(cur.getColumnIndex(Events.DTEND)));
159 this.ContentValues.put(Events.ALL_DAY, cur.getLong(cur.getColumnIndex(Events.ALL_DAY)));
160 this.ContentValues.put(Events.TITLE, cur.getString(cur.getColumnIndex(Events.TITLE)));
161 this.ContentValues.put(Events.CALENDAR_ID, cur.getString(cur.getColumnIndex(Events.CALENDAR_ID)));
162 this.ContentValues.put(Events._SYNC_ID, cur.getString(cur.getColumnIndex(Events._SYNC_ID)));
163 //this.ContentValues.put(Events.SYNC_DATA1, cur.getString(cur.getColumnIndex(Events.SYNC_DATA1))); //not needed here, eTag has already been read
164 this.ContentValues.put(Events.DESCRIPTION, cur.getString(cur.getColumnIndex(Events.DESCRIPTION)));
165 this.ContentValues.put(Events.EVENT_LOCATION, cur.getString(cur.getColumnIndex(Events.EVENT_LOCATION)));
166 this.ContentValues.put(Events.ACCESS_LEVEL, cur.getInt(cur.getColumnIndex(Events.ACCESS_LEVEL)));
168 this.ContentValues.put(Events.STATUS, cur.getInt(cur.getColumnIndex(Events.STATUS)));
170 this.ContentValues.put(Events.LAST_DATE, cur.getInt(cur.getColumnIndex(Events.LAST_DATE)));
171 this.ContentValues.put(Events.DURATION, cur.getString(cur.getColumnIndex(Events.DURATION)));
173 this.ContentValues.put(Events.RDATE, cur.getString(cur.getColumnIndex(Events.RDATE)));
174 this.ContentValues.put(Events.RRULE, cur.getString(cur.getColumnIndex(Events.RRULE)));
175 this.ContentValues.put(Events.EXRULE, cur.getString(cur.getColumnIndex(Events.EXRULE)));
176 this.ContentValues.put(Events.EXDATE, cur.getString(cur.getColumnIndex(Events.EXDATE)));
177 this.ContentValues.put(Events.DIRTY, cur.getInt(cur.getColumnIndex(Events.DIRTY)));
178 this.ContentValues.put(UID, cur.getString(cur.getColumnIndex(UID)));
179 this.ContentValues.put(RAWDATA, cur.getString(cur.getColumnIndex(RAWDATA)));
181 return true;
182 }
184 /**
185 * reads the attendees from a given cursor
186 * @param cur the cursor with the attendees
187 * @return success of this function
188 * @see AndroidEvent#mAttendees
189 */
190 public boolean readAttendees(Cursor cur) {
191 Attendee attendee = null;
192 Organizer organizer = null;
193 ParameterList paraList = null;
195 String Name = "";
196 Cn cn = null;
198 String Email = "";
200 int Relationship = 0;
203 int Status = 0;
204 PartStat partstat = null;
206 int Type = 0;
207 Role role = null;
209 try {
210 while (cur.moveToNext()) {
211 Name = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_NAME));
212 Email = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_EMAIL));
213 Relationship = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_RELATIONSHIP));
214 Type = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_TYPE));
215 Status = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_STATUS));
217 if (Relationship == Attendees.RELATIONSHIP_ORGANIZER) {
218 organizer = new Organizer();
219 organizer.setValue("mailto:" + Email);
220 paraList = organizer.getParameters();
221 mAttendees.add(organizer);
222 } else {
223 attendee = new Attendee();
224 attendee.setValue("mailto:" + Email);
225 paraList = attendee.getParameters();
226 mAttendees.add(attendee);
227 }
229 Rsvp rsvp = new Rsvp(true);
230 paraList.add(rsvp);
232 cn = new Cn(Name);
233 paraList.add(cn);
235 if (Status == Attendees.ATTENDEE_STATUS_INVITED)
236 partstat = new PartStat(PartStat.NEEDS_ACTION.getValue());
237 else if (Status == Attendees.ATTENDEE_STATUS_ACCEPTED)
238 partstat = new PartStat(PartStat.ACCEPTED.getValue());
239 else if (Status == Attendees.ATTENDEE_STATUS_DECLINED)
240 partstat = new PartStat(PartStat.DECLINED.getValue());
241 else if (Status == Attendees.ATTENDEE_STATUS_NONE)
242 partstat = new PartStat(PartStat.COMPLETED.getValue());
243 else if (Status == Attendees.ATTENDEE_STATUS_TENTATIVE)
244 partstat = new PartStat(PartStat.TENTATIVE.getValue());
245 else
246 partstat = new PartStat(PartStat.NEEDS_ACTION.getValue());
247 paraList.add(partstat);
249 if (Type == Attendees.TYPE_OPTIONAL)
250 role = new Role(Role.OPT_PARTICIPANT.getValue());
251 else if (Type == Attendees.TYPE_NONE)
252 role = new Role(Role.NON_PARTICIPANT.getValue()); //regular participants in android are non required?
253 else if (Type == Attendees.TYPE_REQUIRED)
254 role = new Role(Role.REQ_PARTICIPANT.getValue());
255 else
256 role = new Role(Role.NON_PARTICIPANT.getValue());
257 paraList.add(role);
258 }
260 } catch (URISyntaxException e) {
261 e.printStackTrace();
262 }
263 return true;
264 }
266 /**
267 * reads the reminders from a given cursor
268 * @param cur the cursor with the reminders
269 * @return success of this function
270 */
271 public boolean readReminder(Cursor cur) {
272 int Method;
273 int Minutes;
274 VAlarm reminder;
275 while (cur.moveToNext()) {
276 reminder = new VAlarm();
277 Method = cur.getInt(cur.getColumnIndex(Reminders.METHOD));
278 Minutes = cur.getInt(cur.getColumnIndex(Reminders.MINUTES)) * -1;
281 Dur dur = new Dur(0, 0, Minutes, 0);
282 Trigger tri = new Trigger(dur);
283 Value val = new Value(Duration.DURATION);
284 tri.getParameters().add(val);
285 reminder.getProperties().add(tri);
287 Description desc = new Description();
288 desc.setValue("caldavsyncadapter standard description");
289 reminder.getProperties().add(desc);
292 if (Method == Reminders.METHOD_EMAIL)
293 reminder.getProperties().add(Action.EMAIL);
294 else
295 reminder.getProperties().add(Action.DISPLAY);
297 this.mReminders.add(reminder);
298 }
299 return true;
300 }
302 /**
303 * generates a new ics-file.
304 * uses {@link AndroidEvent#ContentValues} as source.
305 * this should only be used when a new event has been generated within android.
306 * @param strUid the UID for this event. example: UID:e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter
307 * @return success of the function
308 * @see CalendarEvent#fetchBody()
309 */
310 public boolean createIcs(String strUid) {
311 boolean Result = false;
312 TimeZone timezone = null;
313 TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
314 //TODO: do not simply create the ics-file new. take into account the RAWDATA if available
315 /*
316 * dtstart=1365598800000
317 * dtend=1365602400000
318 * eventTimezone=Europe/Berlin
319 * eventEndTimezone=null
320 * duration=null
321 * allDay=0
322 * rrule=null
323 * rdate=null
324 * exrule=null
325 * exdate=null
326 * title=Einurlner Termin
327 * description=null
328 * eventLocation=null
329 * accessLevel=0
330 * eventStatus=0
331 *
332 * calendar_id=4
333 * lastDate=-197200128
334 * sync_data1=null
335 * _sync_id=null
336 * dirty=1
337 */
339 try {
340 mCalendar = new Calendar();
341 PropertyList propCalendar = mCalendar.getProperties();
342 propCalendar.add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN"));
343 propCalendar.add(Version.VERSION_2_0);
344 propCalendar.add(CalScale.GREGORIAN);
346 VEvent event = new VEvent();
347 mCalendar.getComponents().add(event);
348 PropertyList propEvent = event.getProperties();
350 // DTSTAMP -> is created by new VEvent() automatical
351 //na
353 // CREATED
354 //na
356 // LAST-MODIFIED
357 //na
359 // SEQUENCE
360 //na
362 // DTSTART
363 long lngStart = this.ContentValues.getAsLong(Events.DTSTART);
364 String strTZStart = this.ContentValues.getAsString(Events.EVENT_TIMEZONE);
365 boolean allDay = this.ContentValues.getAsBoolean(Events.ALL_DAY);
366 if (lngStart > 0) {
367 DtStart dtStart = new DtStart();
368 if (allDay) {
369 Date dateStart = new Date();
370 dateStart.setTime(lngStart);
371 dtStart.setDate(dateStart);
372 } else {
373 DateTime datetimeStart = new DateTime();
374 datetimeStart.setTime(lngStart);
375 dtStart.setDate(datetimeStart);
377 timezone = registry.getTimeZone(strTZStart);
378 dtStart.setTimeZone(timezone);
380 // no timezone information for allDay events
381 mCalendar.getComponents().add(timezone.getVTimeZone());
382 }
383 propEvent.add(dtStart);
384 }
386 // DTEND
387 long lngEnd = this.ContentValues.getAsLong(Events.DTEND);
388 String strTZEnd = this.ContentValues.getAsString(Events.EVENT_END_TIMEZONE);
389 if (strTZEnd == null)
390 strTZEnd = strTZStart;
391 if (lngEnd > 0) {
392 DtEnd dtEnd = new DtEnd();
393 if (allDay) {
394 Date dateEnd = new Date();
395 dateEnd.setTime(lngEnd);
396 dtEnd.setDate(dateEnd);
397 } else {
398 DateTime datetimeEnd = new DateTime();
399 datetimeEnd.setTime(lngEnd);
400 dtEnd.setDate(datetimeEnd);
401 if (strTZEnd != null)
402 timezone = registry.getTimeZone(strTZEnd);
403 dtEnd.setTimeZone(timezone);
404 }
405 propEvent.add(dtEnd);
406 }
408 // DURATION
409 if (this.ContentValues.containsKey(Events.DURATION)) {
410 String strDuration = this.ContentValues.getAsString(Events.DURATION);
411 if (strDuration != null) {
412 Duration duration = new Duration();
413 duration.setValue(strDuration);
415 propEvent.add(duration);
416 }
417 }
419 //RRULE
420 if (this.ContentValues.containsKey(Events.RRULE)) {
421 String strRrule = this.ContentValues.getAsString(Events.RRULE);
422 if (strRrule != null) {
423 if (!strRrule.equals("")) {
424 RRule rrule = new RRule();
425 rrule.setValue(strRrule);
426 propEvent.add(rrule);
427 }
428 }
429 }
431 //RDATE
432 if (this.ContentValues.containsKey(Events.RDATE)) {
433 String strRdate = this.ContentValues.getAsString(Events.RDATE);
434 if (strRdate != null) {
435 if (!strRdate.equals("")) {
436 RDate rdate = new RDate();
437 rdate.setValue(strRdate);
438 propEvent.add(rdate);
439 }
440 }
441 }
443 //EXRULE
444 if (this.ContentValues.containsKey(Events.EXRULE)) {
445 String strExrule = this.ContentValues.getAsString(Events.EXRULE);
446 if (strExrule != null) {
447 if (!strExrule.equals("")) {
448 ExRule exrule = new ExRule();
449 exrule.setValue(strExrule);
450 propEvent.add(exrule);
451 }
452 }
453 }
455 //EXDATE
456 if (this.ContentValues.containsKey(Events.EXDATE)) {
457 String strExdate = this.ContentValues.getAsString(Events.EXDATE);
458 if (strExdate != null) {
459 if (!strExdate.equals("")) {
460 ExDate exdate = new ExDate();
461 exdate.setValue(strExdate);
462 propEvent.add(exdate);
463 }
464 }
465 }
467 //SUMMARY
468 if (this.ContentValues.containsKey(Events.TITLE)) {
469 String strTitle = this.ContentValues.getAsString(Events.TITLE);
470 if (strTitle != null) {
471 Summary summary = new Summary(strTitle);
472 propEvent.add(summary);
473 }
474 }
476 //DESCIPTION
477 if (this.ContentValues.containsKey(Events.DESCRIPTION)) {
478 String strDescription = this.ContentValues.getAsString(Events.DESCRIPTION);
479 if (strDescription != null) {
480 if (!strDescription.equals("")) {
481 Description description = new Description(strDescription);
482 propEvent.add(description);
483 }
484 }
485 }
487 //LOCATION
488 if (this.ContentValues.containsKey(Events.EVENT_LOCATION)) {
489 String strLocation = this.ContentValues.getAsString(Events.EVENT_LOCATION);
490 if (strLocation != null) {
491 if (!strLocation.equals("")) {
492 Location location = new Location(strLocation);
493 propEvent.add(location);
494 }
495 }
496 }
498 //CLASS / ACCESS_LEVEL
499 if (this.ContentValues.containsKey(Events.ACCESS_LEVEL)) {
500 int accessLevel = this.ContentValues.getAsInteger(Events.ACCESS_LEVEL);
501 Clazz clazz = new Clazz();
502 if (accessLevel == Events.ACCESS_PUBLIC)
503 clazz.setValue(Clazz.PUBLIC.getValue());
504 else if (accessLevel == Events.ACCESS_PRIVATE)
505 clazz.setValue(Clazz.PRIVATE.getValue());
506 else if (accessLevel == Events.ACCESS_CONFIDENTIAL)
507 clazz.setValue(Clazz.CONFIDENTIAL.getValue());
508 else
509 clazz.setValue(Clazz.PUBLIC.getValue());
511 propEvent.add(clazz);
512 }
514 //STATUS
515 if (this.ContentValues.containsKey(Events.STATUS)) {
516 int intStatus = this.ContentValues.getAsInteger(Events.STATUS);
517 if (intStatus > -1) {
518 Status status = new Status();
519 if (intStatus == Events.STATUS_CANCELED)
520 status.setValue(Status.VEVENT_CANCELLED.getValue());
521 else if (intStatus == Events.STATUS_CONFIRMED)
522 status.setValue(Status.VEVENT_CONFIRMED.getValue());
523 else if (intStatus == Events.STATUS_TENTATIVE)
524 status.setValue(Status.VEVENT_TENTATIVE.getValue());
526 propEvent.add(status);
527 }
528 }
530 //UID
531 Uid uid = new Uid(strUid);
532 propEvent.add(uid);
534 // Attendees
535 if (mAttendees.size() > 0) {
536 for (Object objProp: mAttendees) {
537 Property prop = (Property) objProp;
538 propEvent.add(prop);
539 }
540 }
542 // Reminders
543 if (mReminders.size() > 0) {
544 for (Object objComp: mReminders) {
545 Component com = (Component) objComp;
546 event.getAlarms().add(com);
547 }
548 }
550 } catch (ParseException e) {
551 e.printStackTrace();
552 }
554 return Result;
555 }
557 /**
558 * marks the android event as already handled
559 * @return
560 * @see AndroidEvent#cInternalTag
561 * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats)
562 * @throws RemoteException
563 */
564 /* public boolean tagAndroidEvent() throws RemoteException {
566 ContentValues values = new ContentValues();
567 values.put(Event.INTERNALTAG, 1);
569 int RowCount = this.mProvider.update(asSyncAdapter(this.getUri(), this.mAccount.name, this.mAccount.type), values, null, null);
570 //Log.e(TAG,"Rows updated: " + RowCount.toString());
572 return (RowCount == 1);
573 }*/
575 /* private static Uri asSyncAdapter(Uri uri, String account, String accountType) {
576 return uri.buildUpon()
577 .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true")
578 .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
579 .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
580 }*/
581 }