CalendarEventModel.java revision 9d8a376b89fcc36c44d4df0c5cbf6991306131c4
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
17package com.android.calendar;
18
19import android.content.Context;
20import android.content.Intent;
21import android.content.SharedPreferences;
22import android.provider.Calendar.Attendees;
23import android.provider.Calendar.Calendars;
24import android.provider.Calendar.Events;
25import android.text.TextUtils;
26
27import java.io.Serializable;
28import java.util.ArrayList;
29import java.util.LinkedHashMap;
30import java.util.TimeZone;
31
32/**
33 * Stores all the information needed to fill out an entry in the events table.
34 * This is a convenient way for storing information needed by the UI to write to
35 * the events table. Only fields that are important to the UI are included.
36 */
37public class CalendarEventModel implements Serializable {
38    public static class Attendee implements Serializable {
39        @Override
40        public int hashCode() {
41            return (mEmail == null) ? 0 : mEmail.hashCode();
42        }
43
44        @Override
45        public boolean equals(Object obj) {
46            if (this == obj) {
47                return true;
48            }
49            if (obj == null) {
50                return false;
51            }
52            if (!(obj instanceof Attendee)) {
53                return false;
54            }
55            Attendee other = (Attendee) obj;
56            if (!TextUtils.equals(mEmail, other.mEmail)) {
57                return false;
58            }
59            return true;
60        }
61
62        public String mName;
63        public String mEmail;
64        public int mStatus;
65
66        public Attendee(String name, String email) {
67            mName = name;
68            mEmail = email;
69            mStatus = Attendees.ATTENDEE_STATUS_NONE;
70        }
71    }
72
73    // TODO strip out fields that don't ever get used
74    /**
75     * The uri of the event in the db. This should only be null for new events.
76     */
77    public String mUri = null;
78    public long mId = -1;
79    public long mCalendarId = -1;
80    public String mCalendarDisplayName = ""; // Make sure this is in sync with the mCalendarId
81    public int mCalendarColor = 0;
82
83    public String mSyncId = null;
84    public String mSyncAccount = null;
85    public String mSyncAccountType = null;
86
87    // PROVIDER_NOTES owner account comes from the calendars table
88    public String mOwnerAccount = null;
89    public String mTitle = null;
90    public String mLocation = null;
91    public String mDescription = null;
92    public String mRrule = null;
93    public String mOrganizer = null;
94    public String mOrganizerDisplayName = null;
95    /**
96     * Read-Only - Derived from other fields
97     */
98    public boolean mIsOrganizer = true;
99    public boolean mIsFirstEventInSeries = true;
100
101    // This should be set the same as mStart when created and is used for making changes to
102    // recurring events. It should not be updated after it is initially set.
103    public long mOriginalStart = -1;
104    public long mStart = -1;
105
106    // This should be set the same as mEnd when created and is used for making changes to
107    // recurring events. It should not be updated after it is initially set.
108    public long mOriginalEnd = -1;
109    public long mEnd = -1;
110    public String mDuration = null;
111    public String mTimezone = null;
112    public String mTimezone2 = null;
113    public boolean mAllDay = false;
114    public boolean mHasAlarm = false;
115    public boolean mTransparency = false;
116
117    // PROVIDER_NOTES How does an event not have attendee data? The owner is added
118    // as an attendee by default.
119    public boolean mHasAttendeeData = true;
120    public int mSelfAttendeeStatus = -1;
121    public int mOwnerAttendeeId = -1;
122    public String mOriginalEvent = null;
123    public Long mOriginalTime = null;
124    public Boolean mOriginalAllDay = null;
125    public boolean mGuestsCanModify = false;
126    public boolean mGuestsCanInviteOthers = false;
127    public boolean mGuestsCanSeeGuests = false;
128
129    public boolean mOrganizerCanRespond = false;
130    public int mCalendarAccessLevel = Calendars.CONTRIBUTOR_ACCESS;
131
132    // The model can't be updated with a calendar cursor until it has been
133    // updated with an event cursor.
134    public boolean mModelUpdatedWithEventCursor;
135
136    public int mVisibility = 0;
137    public ArrayList<Integer> mReminderMinutes;
138
139    // PROVIDER_NOTES Using EditEventHelper the owner should not be included in this
140    // list and will instead be added by saveEvent. Is this what we want?
141    public LinkedHashMap<String, Attendee> mAttendeesList;
142
143    public CalendarEventModel() {
144        mReminderMinutes = new ArrayList<Integer>();
145        mAttendeesList = new LinkedHashMap<String, Attendee>();
146        mTimezone = TimeZone.getDefault().getID();
147    }
148
149    public CalendarEventModel(Context context) {
150        this();
151
152        mTimezone = Utils.getTimeZone(context, null);
153        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
154
155        String defaultReminder = prefs.getString(
156                GeneralPreferences.KEY_DEFAULT_REMINDER, GeneralPreferences.NO_REMINDER_STRING);
157        int defaultReminderMins = Integer.parseInt(defaultReminder);
158        if (defaultReminderMins != GeneralPreferences.NO_REMINDER) {
159            mHasAlarm = true;
160            mReminderMinutes.add(defaultReminderMins);
161        }
162    }
163
164    public CalendarEventModel(Context context, Intent intent) {
165        this(context);
166
167        String title = intent.getStringExtra(Events.TITLE);
168        if (title != null) {
169            mTitle = title;
170        }
171
172        String location = intent.getStringExtra(Events.EVENT_LOCATION);
173        if (location != null) {
174            mLocation = location;
175        }
176
177        String description = intent.getStringExtra(Events.DESCRIPTION);
178        if (description != null) {
179            mDescription = description;
180        }
181
182        int transparency = intent.getIntExtra(Events.TRANSPARENCY, -1);
183        if (transparency != -1) {
184            mTransparency = transparency != 0;
185        }
186
187        int visibility = intent.getIntExtra(Events.VISIBILITY, -1);
188        if (visibility != -1) {
189            mVisibility = visibility;
190        }
191
192        String rrule = intent.getStringExtra(Events.RRULE);
193        if (!TextUtils.isEmpty(rrule)) {
194            mRrule = rrule;
195        }
196    }
197
198    public boolean isValid() {
199        if (mCalendarId == -1) {
200            return false;
201        }
202        if (TextUtils.isEmpty(mOwnerAccount)) {
203            return false;
204        }
205        return true;
206    }
207
208    private boolean isEmpty() {
209        if (mTitle != null && mTitle.length() > 0) {
210            return false;
211        }
212
213        if (mLocation != null && mLocation.length() > 0) {
214            return false;
215        }
216
217        if (mDescription != null && mDescription.length() > 0) {
218            return false;
219        }
220
221        return true;
222    }
223
224    public void clear() {
225        mUri = null;
226        mId = -1;
227        mCalendarId = -1;
228
229        mSyncId = null;
230        mSyncAccount = null;
231        mSyncAccountType = null;
232        mOwnerAccount = null;
233
234        mTitle = null;
235        mLocation = null;
236        mDescription = null;
237        mRrule = null;
238        mOrganizer = null;
239        mOrganizerDisplayName = null;
240        mIsOrganizer = true;
241        mIsFirstEventInSeries = true;
242
243        mOriginalStart = -1;
244        mStart = -1;
245        mOriginalEnd = -1;
246        mEnd = -1;
247        mDuration = null;
248        mTimezone = null;
249        mTimezone2 = null;
250        mAllDay = false;
251        mHasAlarm = false;
252
253        mHasAttendeeData = true;
254        mSelfAttendeeStatus = -1;
255        mOwnerAttendeeId = -1;
256        mOriginalEvent = null;
257        mOriginalTime = null;
258        mOriginalAllDay = null;
259
260        mGuestsCanModify = false;
261        mGuestsCanInviteOthers = false;
262        mGuestsCanSeeGuests = false;
263        mVisibility = 0;
264        mOrganizerCanRespond = false;
265        mCalendarAccessLevel = Calendars.CONTRIBUTOR_ACCESS;
266        mModelUpdatedWithEventCursor = false;
267
268        mReminderMinutes = new ArrayList<Integer>();
269        mAttendeesList.clear();
270    }
271
272    public void addAttendee(Attendee attendee) {
273        mAttendeesList.put(attendee.mEmail, attendee);
274    }
275
276    public void removeAttendee(Attendee attendee) {
277        mAttendeesList.remove(attendee.mEmail);
278    }
279
280    public String getAttendeesString() {
281        StringBuilder b = new StringBuilder();
282        for (Attendee attendee : mAttendeesList.values()) {
283            String name = attendee.mName;
284            String email = attendee.mEmail;
285            String status = Integer.toString(attendee.mStatus);
286            b.append("name:").append(name);
287            b.append(" email:").append(email);
288            b.append(" status:").append(status);
289        }
290        return b.toString();
291    }
292
293    @Override
294    public int hashCode() {
295        final int prime = 31;
296        int result = 1;
297        result = prime * result + (mAllDay ? 1231 : 1237);
298        result = prime * result + ((mAttendeesList == null) ? 0 : getAttendeesString().hashCode());
299        result = prime * result + (int) (mCalendarId ^ (mCalendarId >>> 32));
300        result = prime * result + ((mDescription == null) ? 0 : mDescription.hashCode());
301        result = prime * result + ((mDuration == null) ? 0 : mDuration.hashCode());
302        result = prime * result + (int) (mEnd ^ (mEnd >>> 32));
303        result = prime * result + (mGuestsCanInviteOthers ? 1231 : 1237);
304        result = prime * result + (mGuestsCanModify ? 1231 : 1237);
305        result = prime * result + (mGuestsCanSeeGuests ? 1231 : 1237);
306        result = prime * result + (mOrganizerCanRespond ? 1231 : 1237);
307        result = prime * result + (mModelUpdatedWithEventCursor ? 1231 : 1237);
308        result = prime * result + mCalendarAccessLevel;
309        result = prime * result + (mHasAlarm ? 1231 : 1237);
310        result = prime * result + (mHasAttendeeData ? 1231 : 1237);
311        result = prime * result + (int) (mId ^ (mId >>> 32));
312        result = prime * result + (mIsFirstEventInSeries ? 1231 : 1237);
313        result = prime * result + (mIsOrganizer ? 1231 : 1237);
314        result = prime * result + ((mLocation == null) ? 0 : mLocation.hashCode());
315        result = prime * result + ((mOrganizer == null) ? 0 : mOrganizer.hashCode());
316        result = prime * result + ((mOriginalAllDay == null) ? 0 : mOriginalAllDay.hashCode());
317        result = prime * result + (int) (mOriginalEnd ^ (mOriginalEnd >>> 32));
318        result = prime * result + ((mOriginalEvent == null) ? 0 : mOriginalEvent.hashCode());
319        result = prime * result + (int) (mOriginalStart ^ (mOriginalStart >>> 32));
320        result = prime * result + ((mOriginalTime == null) ? 0 : mOriginalTime.hashCode());
321        result = prime * result + ((mOwnerAccount == null) ? 0 : mOwnerAccount.hashCode());
322        result = prime * result + ((mReminderMinutes == null) ? 0 : mReminderMinutes.hashCode());
323        result = prime * result + ((mRrule == null) ? 0 : mRrule.hashCode());
324        result = prime * result + mSelfAttendeeStatus;
325        result = prime * result + mOwnerAttendeeId;
326        result = prime * result + (int) (mStart ^ (mStart >>> 32));
327        result = prime * result + ((mSyncAccount == null) ? 0 : mSyncAccount.hashCode());
328        result = prime * result + ((mSyncAccountType == null) ? 0 : mSyncAccountType.hashCode());
329        result = prime * result + ((mSyncId == null) ? 0 : mSyncId.hashCode());
330        result = prime * result + ((mTimezone == null) ? 0 : mTimezone.hashCode());
331        result = prime * result + ((mTimezone2 == null) ? 0 : mTimezone2.hashCode());
332        result = prime * result + ((mTitle == null) ? 0 : mTitle.hashCode());
333        result = prime * result + (mTransparency ? 1231 : 1237);
334        result = prime * result + ((mUri == null) ? 0 : mUri.hashCode());
335        result = prime * result + mVisibility;
336        return result;
337    }
338
339    // Autogenerated equals method
340    @Override
341    public boolean equals(Object obj) {
342        if (this == obj) {
343            return true;
344        }
345        if (obj == null) {
346            return false;
347        }
348        if (!(obj instanceof CalendarEventModel)) {
349            return false;
350        }
351
352        CalendarEventModel other = (CalendarEventModel) obj;
353        if (!checkOriginalModelFields(other)) {
354            return false;
355        }
356
357        if (mEnd != other.mEnd) {
358            return false;
359        }
360        if (mIsFirstEventInSeries != other.mIsFirstEventInSeries) {
361            return false;
362        }
363        if (mOriginalEnd != other.mOriginalEnd) {
364            return false;
365        }
366
367        if (mOriginalStart != other.mOriginalStart) {
368            return false;
369        }
370        if (mStart != other.mStart) {
371            return false;
372        }
373
374        if (mOriginalEvent == null) {
375            if (other.mOriginalEvent != null) {
376                return false;
377            }
378        } else if (!mOriginalEvent.equals(other.mOriginalEvent)) {
379            return false;
380        }
381
382        if (mRrule == null) {
383            if (other.mRrule != null) {
384                return false;
385            }
386        } else if (!mRrule.equals(other.mRrule)) {
387            return false;
388        }
389        return true;
390    }
391
392    /**
393     * Whether the event has been modified based on its original model.
394     *
395     * @param originalModel
396     * @return true if the model is unchanged, false otherwise
397     */
398    public boolean isUnchanged(CalendarEventModel originalModel) {
399        if (this == originalModel) {
400            return true;
401        }
402        if (originalModel == null) {
403            return false;
404        }
405
406        if (!checkOriginalModelFields(originalModel)) {
407            return false;
408        }
409        if (mEnd != mOriginalEnd) {
410            return false;
411        }
412        if (mStart != mOriginalStart) {
413            return false;
414        }
415
416        if (mRrule == null) {
417            if (originalModel.mRrule != null) {
418                if (mOriginalEvent == null || !mOriginalEvent.equals(originalModel.mSyncId)) {
419                    return false;
420                }
421            }
422        } else if (!mRrule.equals(originalModel.mRrule)) {
423            return false;
424        }
425
426        return true;
427    }
428
429    /**
430     * Checks against an original model for changes to an event. This covers all
431     * the fields that should remain consistent between an original event model
432     * and the new one if nothing in the event was modified. This is also the
433     * portion that overlaps with equality between two event models.
434     *
435     * @param originalModel
436     * @return true if these fields are unchanged, false otherwise
437     */
438    protected boolean checkOriginalModelFields(CalendarEventModel originalModel) {
439        if (mAllDay != originalModel.mAllDay) {
440            return false;
441        }
442        if (mAttendeesList == null) {
443            if (originalModel.mAttendeesList != null) {
444                return false;
445            }
446        } else if (!mAttendeesList.equals(originalModel.mAttendeesList)) {
447            return false;
448        }
449
450        if (mCalendarId != originalModel.mCalendarId) {
451            return false;
452        }
453
454        if (mDescription == null) {
455            if (originalModel.mDescription != null) {
456                return false;
457            }
458        } else if (!mDescription.equals(originalModel.mDescription)) {
459            return false;
460        }
461
462        if (mDuration == null) {
463            if (originalModel.mDuration != null) {
464                return false;
465            }
466        } else if (!mDuration.equals(originalModel.mDuration)) {
467            return false;
468        }
469
470        if (mGuestsCanInviteOthers != originalModel.mGuestsCanInviteOthers) {
471            return false;
472        }
473        if (mGuestsCanModify != originalModel.mGuestsCanModify) {
474            return false;
475        }
476        if (mGuestsCanSeeGuests != originalModel.mGuestsCanSeeGuests) {
477            return false;
478        }
479        if (mOrganizerCanRespond != originalModel.mOrganizerCanRespond) {
480            return false;
481        }
482        if (mCalendarAccessLevel != originalModel.mCalendarAccessLevel) {
483            return false;
484        }
485        if (mModelUpdatedWithEventCursor != originalModel.mModelUpdatedWithEventCursor) {
486            return false;
487        }
488        if (mHasAlarm != originalModel.mHasAlarm) {
489            return false;
490        }
491        if (mHasAttendeeData != originalModel.mHasAttendeeData) {
492            return false;
493        }
494        if (mId != originalModel.mId) {
495            return false;
496        }
497        if (mIsOrganizer != originalModel.mIsOrganizer) {
498            return false;
499        }
500
501        if (mLocation == null) {
502            if (originalModel.mLocation != null) {
503                return false;
504            }
505        } else if (!mLocation.equals(originalModel.mLocation)) {
506            return false;
507        }
508
509        if (mOrganizer == null) {
510            if (originalModel.mOrganizer != null) {
511                return false;
512            }
513        } else if (!mOrganizer.equals(originalModel.mOrganizer)) {
514            return false;
515        }
516
517        if (mOriginalAllDay == null) {
518            if (originalModel.mOriginalAllDay != null) {
519                return false;
520            }
521        } else if (!mOriginalAllDay.equals(originalModel.mOriginalAllDay)) {
522            return false;
523        }
524
525        if (mOriginalTime == null) {
526            if (originalModel.mOriginalTime != null) {
527                return false;
528            }
529        } else if (!mOriginalTime.equals(originalModel.mOriginalTime)) {
530            return false;
531        }
532
533        if (mOwnerAccount == null) {
534            if (originalModel.mOwnerAccount != null) {
535                return false;
536            }
537        } else if (!mOwnerAccount.equals(originalModel.mOwnerAccount)) {
538            return false;
539        }
540
541        if (mReminderMinutes == null) {
542            if (originalModel.mReminderMinutes != null) {
543                return false;
544            }
545        } else if (!mReminderMinutes.equals(originalModel.mReminderMinutes)) {
546            return false;
547        }
548
549        if (mSelfAttendeeStatus != originalModel.mSelfAttendeeStatus) {
550            return false;
551        }
552        if (mOwnerAttendeeId != originalModel.mOwnerAttendeeId) {
553            return false;
554        }
555        if (mSyncAccount == null) {
556            if (originalModel.mSyncAccount != null) {
557                return false;
558            }
559        } else if (!mSyncAccount.equals(originalModel.mSyncAccount)) {
560            return false;
561        }
562
563        if (mSyncAccountType == null) {
564            if (originalModel.mSyncAccountType != null) {
565                return false;
566            }
567        } else if (!mSyncAccountType.equals(originalModel.mSyncAccountType)) {
568            return false;
569        }
570
571        if (mSyncId == null) {
572            if (originalModel.mSyncId != null) {
573                return false;
574            }
575        } else if (!mSyncId.equals(originalModel.mSyncId)) {
576            return false;
577        }
578
579        if (mTimezone == null) {
580            if (originalModel.mTimezone != null) {
581                return false;
582            }
583        } else if (!mTimezone.equals(originalModel.mTimezone)) {
584            return false;
585        }
586
587        if (mTimezone2 == null) {
588            if (originalModel.mTimezone2 != null) {
589                return false;
590            }
591        } else if (!mTimezone2.equals(originalModel.mTimezone2)) {
592            return false;
593        }
594
595        if (mTitle == null) {
596            if (originalModel.mTitle != null) {
597                return false;
598            }
599        } else if (!mTitle.equals(originalModel.mTitle)) {
600            return false;
601        }
602
603        if (mTransparency != originalModel.mTransparency) {
604            return false;
605        }
606
607        if (mUri == null) {
608            if (originalModel.mUri != null) {
609                return false;
610            }
611        } else if (!mUri.equals(originalModel.mUri)) {
612            return false;
613        }
614
615        if (mVisibility != originalModel.mVisibility) {
616            return false;
617        }
618        return true;
619    }
620}
621