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 
17 package com.android.calendar;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.SharedPreferences;
22 import android.provider.CalendarContract.Attendees;
23 import android.provider.CalendarContract.Calendars;
24 import android.provider.CalendarContract.Events;
25 import android.provider.CalendarContract.Reminders;
26 import android.text.TextUtils;
27 import android.text.util.Rfc822Token;
28 
29 import com.android.calendar.event.EditEventHelper;
30 import com.android.calendar.event.EventColorCache;
31 import com.android.common.Rfc822Validator;
32 
33 import java.io.Serializable;
34 import java.util.ArrayList;
35 import java.util.Collections;
36 import java.util.LinkedHashMap;
37 import java.util.LinkedHashSet;
38 import java.util.TimeZone;
39 
40 /**
41  * Stores all the information needed to fill out an entry in the events table.
42  * This is a convenient way for storing information needed by the UI to write to
43  * the events table. Only fields that are important to the UI are included.
44  */
45 public class CalendarEventModel implements Serializable {
46     private static final String TAG = "CalendarEventModel";
47 
48     public static class Attendee implements Serializable {
49         @Override
hashCode()50         public int hashCode() {
51             return (mEmail == null) ? 0 : mEmail.hashCode();
52         }
53 
54         @Override
equals(Object obj)55         public boolean equals(Object obj) {
56             if (this == obj) {
57                 return true;
58             }
59             if (!(obj instanceof Attendee)) {
60                 return false;
61             }
62             Attendee other = (Attendee) obj;
63             if (!TextUtils.equals(mEmail, other.mEmail)) {
64                 return false;
65             }
66             return true;
67         }
68 
getDisplayName()69         String getDisplayName() {
70             if (TextUtils.isEmpty(mName)) {
71                 return mEmail;
72             } else {
73                 return mName;
74             }
75         }
76 
77         public String mName;
78         public String mEmail;
79         public int mStatus;
80         public String mIdentity;
81         public String mIdNamespace;
82 
Attendee(String name, String email)83         public Attendee(String name, String email) {
84             this(name, email, Attendees.ATTENDEE_STATUS_NONE, null, null);
85         }
Attendee(String name, String email, int status, String identity, String idNamespace)86         public Attendee(String name, String email, int status, String identity,
87                 String idNamespace) {
88             mName = name;
89             mEmail = email;
90             mStatus = status;
91             mIdentity = identity;
92             mIdNamespace = idNamespace;
93         }
94     }
95 
96     /**
97      * A single reminder entry.
98      *
99      * Instances of the class are immutable.
100      */
101     public static class ReminderEntry implements Comparable<ReminderEntry>, Serializable {
102         private final int mMinutes;
103         private final int mMethod;
104 
105         /**
106          * Returns a new ReminderEntry, with the specified minutes and method.
107          *
108          * @param minutes Number of minutes before the start of the event that the alert will fire.
109          * @param method Type of alert ({@link Reminders#METHOD_ALERT}, etc).
110          */
valueOf(int minutes, int method)111         public static ReminderEntry valueOf(int minutes, int method) {
112             // TODO: cache common instances
113             return new ReminderEntry(minutes, method);
114         }
115 
116         /**
117          * Returns a ReminderEntry, with the specified number of minutes and a default alert method.
118          *
119          * @param minutes Number of minutes before the start of the event that the alert will fire.
120          */
valueOf(int minutes)121         public static ReminderEntry valueOf(int minutes) {
122             return valueOf(minutes, Reminders.METHOD_DEFAULT);
123         }
124 
125         /**
126          * Constructs a new ReminderEntry.
127          *
128          * @param minutes Number of minutes before the start of the event that the alert will fire.
129          * @param method Type of alert ({@link Reminders#METHOD_ALERT}, etc).
130          */
ReminderEntry(int minutes, int method)131         private ReminderEntry(int minutes, int method) {
132             // TODO: error-check args
133             mMinutes = minutes;
134             mMethod = method;
135         }
136 
137         @Override
hashCode()138         public int hashCode() {
139             return mMinutes * 10 + mMethod;
140         }
141 
142         @Override
equals(Object obj)143         public boolean equals(Object obj) {
144             if (this == obj) {
145                 return true;
146             }
147             if (!(obj instanceof ReminderEntry)) {
148                 return false;
149             }
150 
151             ReminderEntry re = (ReminderEntry) obj;
152 
153             if (re.mMinutes != mMinutes) {
154                 return false;
155             }
156 
157             // Treat ALERT and DEFAULT as equivalent.  This is useful during the "has anything
158             // "changed" test, so that if DEFAULT is present, but we don't change anything,
159             // the internal conversion of DEFAULT to ALERT doesn't force a database update.
160             return re.mMethod == mMethod ||
161                 (re.mMethod == Reminders.METHOD_DEFAULT && mMethod == Reminders.METHOD_ALERT) ||
162                 (re.mMethod == Reminders.METHOD_ALERT && mMethod == Reminders.METHOD_DEFAULT);
163         }
164 
165         @Override
toString()166         public String toString() {
167             return "ReminderEntry min=" + mMinutes + " meth=" + mMethod;
168         }
169 
170         /**
171          * Comparison function for a sort ordered primarily descending by minutes,
172          * secondarily ascending by method type.
173          */
174         @Override
compareTo(ReminderEntry re)175         public int compareTo(ReminderEntry re) {
176             if (re.mMinutes != mMinutes) {
177                 return re.mMinutes - mMinutes;
178             }
179             if (re.mMethod != mMethod) {
180                 return mMethod - re.mMethod;
181             }
182             return 0;
183         }
184 
185         /** Returns the minutes. */
getMinutes()186         public int getMinutes() {
187             return mMinutes;
188         }
189 
190         /** Returns the alert method. */
getMethod()191         public int getMethod() {
192             return mMethod;
193         }
194     }
195 
196     // TODO strip out fields that don't ever get used
197     /**
198      * The uri of the event in the db. This should only be null for new events.
199      */
200     public String mUri = null;
201     public long mId = -1;
202     public long mCalendarId = -1;
203     public String mCalendarDisplayName = ""; // Make sure this is in sync with the mCalendarId
204     private int mCalendarColor = -1;
205     private boolean mCalendarColorInitialized = false;
206     public String mCalendarAccountName;
207     public String mCalendarAccountType;
208     public int mCalendarMaxReminders;
209     public String mCalendarAllowedReminders;
210     public String mCalendarAllowedAttendeeTypes;
211     public String mCalendarAllowedAvailability;
212 
213     public String mSyncId = null;
214     public String mSyncAccount = null;
215     public String mSyncAccountType = null;
216 
217     public EventColorCache mEventColorCache;
218     private int mEventColor = -1;
219     private boolean mEventColorInitialized = false;
220 
221     // PROVIDER_NOTES owner account comes from the calendars table
222     public String mOwnerAccount = null;
223     public String mTitle = null;
224     public String mLocation = null;
225     public String mDescription = null;
226     public String mRrule = null;
227     public String mOrganizer = null;
228     public String mOrganizerDisplayName = null;
229     /**
230      * Read-Only - Derived from other fields
231      */
232     public boolean mIsOrganizer = true;
233     public boolean mIsFirstEventInSeries = true;
234 
235     // This should be set the same as mStart when created and is used for making changes to
236     // recurring events. It should not be updated after it is initially set.
237     public long mOriginalStart = -1;
238     public long mStart = -1;
239 
240     // This should be set the same as mEnd when created and is used for making changes to
241     // recurring events. It should not be updated after it is initially set.
242     public long mOriginalEnd = -1;
243     public long mEnd = -1;
244     public String mDuration = null;
245     public String mTimezone = null;
246     public String mTimezone2 = null;
247     public boolean mAllDay = false;
248     public boolean mHasAlarm = false;
249     public int mAvailability = Events.AVAILABILITY_BUSY;
250 
251     // PROVIDER_NOTES How does an event not have attendee data? The owner is added
252     // as an attendee by default.
253     public boolean mHasAttendeeData = true;
254     public int mSelfAttendeeStatus = -1;
255     public int mOwnerAttendeeId = -1;
256     public String mOriginalSyncId = null;
257     public long mOriginalId = -1;
258     public Long mOriginalTime = null;
259     public Boolean mOriginalAllDay = null;
260     public boolean mGuestsCanModify = false;
261     public boolean mGuestsCanInviteOthers = false;
262     public boolean mGuestsCanSeeGuests = false;
263 
264     public boolean mOrganizerCanRespond = false;
265     public int mCalendarAccessLevel = Calendars.CAL_ACCESS_CONTRIBUTOR;
266 
267     public int mEventStatus = Events.STATUS_CONFIRMED;
268 
269     // The model can't be updated with a calendar cursor until it has been
270     // updated with an event cursor.
271     public boolean mModelUpdatedWithEventCursor;
272 
273     public int mAccessLevel = 0;
274     public ArrayList<ReminderEntry> mReminders;
275     public ArrayList<ReminderEntry> mDefaultReminders;
276 
277     // PROVIDER_NOTES Using EditEventHelper the owner should not be included in this
278     // list and will instead be added by saveEvent. Is this what we want?
279     public LinkedHashMap<String, Attendee> mAttendeesList;
280 
CalendarEventModel()281     public CalendarEventModel() {
282         mReminders = new ArrayList<ReminderEntry>();
283         mDefaultReminders = new ArrayList<ReminderEntry>();
284         mAttendeesList = new LinkedHashMap<String, Attendee>();
285         mTimezone = TimeZone.getDefault().getID();
286     }
287 
CalendarEventModel(Context context)288     public CalendarEventModel(Context context) {
289         this();
290 
291         mTimezone = Utils.getTimeZone(context, null);
292         SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
293 
294         String defaultReminder = prefs.getString(
295                 GeneralPreferences.KEY_DEFAULT_REMINDER, GeneralPreferences.NO_REMINDER_STRING);
296         int defaultReminderMins = Integer.parseInt(defaultReminder);
297         if (defaultReminderMins != GeneralPreferences.NO_REMINDER) {
298             // Assume all calendars allow at least one reminder.
299             mHasAlarm = true;
300             mReminders.add(ReminderEntry.valueOf(defaultReminderMins));
301             mDefaultReminders.add(ReminderEntry.valueOf(defaultReminderMins));
302         }
303     }
304 
CalendarEventModel(Context context, Intent intent)305     public CalendarEventModel(Context context, Intent intent) {
306         this(context);
307 
308         if (intent == null) {
309             return;
310         }
311 
312         String title = intent.getStringExtra(Events.TITLE);
313         if (title != null) {
314             mTitle = title;
315         }
316 
317         String location = intent.getStringExtra(Events.EVENT_LOCATION);
318         if (location != null) {
319             mLocation = location;
320         }
321 
322         String description = intent.getStringExtra(Events.DESCRIPTION);
323         if (description != null) {
324             mDescription = description;
325         }
326 
327         int availability = intent.getIntExtra(Events.AVAILABILITY, -1);
328         if (availability != -1) {
329             mAvailability = availability;
330         }
331 
332         int accessLevel = intent.getIntExtra(Events.ACCESS_LEVEL, -1);
333         if (accessLevel != -1) {
334             if (accessLevel > 0) {
335                 // TODO remove this if we add support for
336                 // Events.ACCESS_CONFIDENTIAL
337                 accessLevel--;
338             }
339             mAccessLevel = accessLevel;
340         }
341 
342         String rrule = intent.getStringExtra(Events.RRULE);
343         if (!TextUtils.isEmpty(rrule)) {
344             mRrule = rrule;
345         }
346 
347         String emails = intent.getStringExtra(Intent.EXTRA_EMAIL);
348         if (!TextUtils.isEmpty(emails)) {
349             String[] emailArray = emails.split("[ ,;]");
350             for (String email : emailArray) {
351                 if (!TextUtils.isEmpty(email) && email.contains("@")) {
352                     email = email.trim();
353                     if (!mAttendeesList.containsKey(email)) {
354                         mAttendeesList.put(email, new Attendee("", email));
355                     }
356                 }
357             }
358         }
359     }
360 
isValid()361     public boolean isValid() {
362         if (mCalendarId == -1) {
363             return false;
364         }
365         if (TextUtils.isEmpty(mOwnerAccount)) {
366             return false;
367         }
368         return true;
369     }
370 
isEmpty()371     public boolean isEmpty() {
372         if (mTitle != null && mTitle.trim().length() > 0) {
373             return false;
374         }
375 
376         if (mLocation != null && mLocation.trim().length() > 0) {
377             return false;
378         }
379 
380         if (mDescription != null && mDescription.trim().length() > 0) {
381             return false;
382         }
383 
384         return true;
385     }
386 
clear()387     public void clear() {
388         mUri = null;
389         mId = -1;
390         mCalendarId = -1;
391         mCalendarColor = -1;
392         mCalendarColorInitialized = false;
393 
394         mEventColorCache = null;
395         mEventColor = -1;
396         mEventColorInitialized = false;
397 
398         mSyncId = null;
399         mSyncAccount = null;
400         mSyncAccountType = null;
401         mOwnerAccount = null;
402 
403         mTitle = null;
404         mLocation = null;
405         mDescription = null;
406         mRrule = null;
407         mOrganizer = null;
408         mOrganizerDisplayName = null;
409         mIsOrganizer = true;
410         mIsFirstEventInSeries = true;
411 
412         mOriginalStart = -1;
413         mStart = -1;
414         mOriginalEnd = -1;
415         mEnd = -1;
416         mDuration = null;
417         mTimezone = null;
418         mTimezone2 = null;
419         mAllDay = false;
420         mHasAlarm = false;
421 
422         mHasAttendeeData = true;
423         mSelfAttendeeStatus = -1;
424         mOwnerAttendeeId = -1;
425         mOriginalId = -1;
426         mOriginalSyncId = null;
427         mOriginalTime = null;
428         mOriginalAllDay = null;
429 
430         mGuestsCanModify = false;
431         mGuestsCanInviteOthers = false;
432         mGuestsCanSeeGuests = false;
433         mAccessLevel = 0;
434         mEventStatus = Events.STATUS_CONFIRMED;
435         mOrganizerCanRespond = false;
436         mCalendarAccessLevel = Calendars.CAL_ACCESS_CONTRIBUTOR;
437         mModelUpdatedWithEventCursor = false;
438         mCalendarAllowedReminders = null;
439         mCalendarAllowedAttendeeTypes = null;
440         mCalendarAllowedAvailability = null;
441 
442         mReminders = new ArrayList<ReminderEntry>();
443         mAttendeesList.clear();
444     }
445 
addAttendee(Attendee attendee)446     public void addAttendee(Attendee attendee) {
447         mAttendeesList.put(attendee.mEmail, attendee);
448     }
449 
addAttendees(String attendees, Rfc822Validator validator)450     public void addAttendees(String attendees, Rfc822Validator validator) {
451         final LinkedHashSet<Rfc822Token> addresses = EditEventHelper.getAddressesFromList(
452                 attendees, validator);
453         synchronized (this) {
454             for (final Rfc822Token address : addresses) {
455                 final Attendee attendee = new Attendee(address.getName(), address.getAddress());
456                 if (TextUtils.isEmpty(attendee.mName)) {
457                     attendee.mName = attendee.mEmail;
458                 }
459                 addAttendee(attendee);
460             }
461         }
462     }
463 
removeAttendee(Attendee attendee)464     public void removeAttendee(Attendee attendee) {
465         mAttendeesList.remove(attendee.mEmail);
466     }
467 
getAttendeesString()468     public String getAttendeesString() {
469         StringBuilder b = new StringBuilder();
470         for (Attendee attendee : mAttendeesList.values()) {
471             String name = attendee.mName;
472             String email = attendee.mEmail;
473             String status = Integer.toString(attendee.mStatus);
474             b.append("name:").append(name);
475             b.append(" email:").append(email);
476             b.append(" status:").append(status);
477         }
478         return b.toString();
479     }
480 
481     @Override
hashCode()482     public int hashCode() {
483         final int prime = 31;
484         int result = 1;
485         result = prime * result + (mAllDay ? 1231 : 1237);
486         result = prime * result + ((mAttendeesList == null) ? 0 : getAttendeesString().hashCode());
487         result = prime * result + (int) (mCalendarId ^ (mCalendarId >>> 32));
488         result = prime * result + ((mDescription == null) ? 0 : mDescription.hashCode());
489         result = prime * result + ((mDuration == null) ? 0 : mDuration.hashCode());
490         result = prime * result + (int) (mEnd ^ (mEnd >>> 32));
491         result = prime * result + (mGuestsCanInviteOthers ? 1231 : 1237);
492         result = prime * result + (mGuestsCanModify ? 1231 : 1237);
493         result = prime * result + (mGuestsCanSeeGuests ? 1231 : 1237);
494         result = prime * result + (mOrganizerCanRespond ? 1231 : 1237);
495         result = prime * result + (mModelUpdatedWithEventCursor ? 1231 : 1237);
496         result = prime * result + mCalendarAccessLevel;
497         result = prime * result + (mHasAlarm ? 1231 : 1237);
498         result = prime * result + (mHasAttendeeData ? 1231 : 1237);
499         result = prime * result + (int) (mId ^ (mId >>> 32));
500         result = prime * result + (mIsFirstEventInSeries ? 1231 : 1237);
501         result = prime * result + (mIsOrganizer ? 1231 : 1237);
502         result = prime * result + ((mLocation == null) ? 0 : mLocation.hashCode());
503         result = prime * result + ((mOrganizer == null) ? 0 : mOrganizer.hashCode());
504         result = prime * result + ((mOriginalAllDay == null) ? 0 : mOriginalAllDay.hashCode());
505         result = prime * result + (int) (mOriginalEnd ^ (mOriginalEnd >>> 32));
506         result = prime * result + ((mOriginalSyncId == null) ? 0 : mOriginalSyncId.hashCode());
507         result = prime * result + (int) (mOriginalId ^ (mOriginalEnd >>> 32));
508         result = prime * result + (int) (mOriginalStart ^ (mOriginalStart >>> 32));
509         result = prime * result + ((mOriginalTime == null) ? 0 : mOriginalTime.hashCode());
510         result = prime * result + ((mOwnerAccount == null) ? 0 : mOwnerAccount.hashCode());
511         result = prime * result + ((mReminders == null) ? 0 : mReminders.hashCode());
512         result = prime * result + ((mRrule == null) ? 0 : mRrule.hashCode());
513         result = prime * result + mSelfAttendeeStatus;
514         result = prime * result + mOwnerAttendeeId;
515         result = prime * result + (int) (mStart ^ (mStart >>> 32));
516         result = prime * result + ((mSyncAccount == null) ? 0 : mSyncAccount.hashCode());
517         result = prime * result + ((mSyncAccountType == null) ? 0 : mSyncAccountType.hashCode());
518         result = prime * result + ((mSyncId == null) ? 0 : mSyncId.hashCode());
519         result = prime * result + ((mTimezone == null) ? 0 : mTimezone.hashCode());
520         result = prime * result + ((mTimezone2 == null) ? 0 : mTimezone2.hashCode());
521         result = prime * result + ((mTitle == null) ? 0 : mTitle.hashCode());
522         result = prime * result + (mAvailability);
523         result = prime * result + ((mUri == null) ? 0 : mUri.hashCode());
524         result = prime * result + mAccessLevel;
525         result = prime * result + mEventStatus;
526         return result;
527     }
528 
529     // Autogenerated equals method
530     @Override
equals(Object obj)531     public boolean equals(Object obj) {
532         if (this == obj) {
533             return true;
534         }
535         if (obj == null) {
536             return false;
537         }
538         if (!(obj instanceof CalendarEventModel)) {
539             return false;
540         }
541 
542         CalendarEventModel other = (CalendarEventModel) obj;
543         if (!checkOriginalModelFields(other)) {
544             return false;
545         }
546 
547         if (mLocation == null) {
548             if (other.mLocation != null) {
549                 return false;
550             }
551         } else if (!mLocation.equals(other.mLocation)) {
552             return false;
553         }
554 
555         if (mTitle == null) {
556             if (other.mTitle != null) {
557                 return false;
558             }
559         } else if (!mTitle.equals(other.mTitle)) {
560             return false;
561         }
562 
563         if (mDescription == null) {
564             if (other.mDescription != null) {
565                 return false;
566             }
567         } else if (!mDescription.equals(other.mDescription)) {
568             return false;
569         }
570 
571         if (mDuration == null) {
572             if (other.mDuration != null) {
573                 return false;
574             }
575         } else if (!mDuration.equals(other.mDuration)) {
576             return false;
577         }
578 
579         if (mEnd != other.mEnd) {
580             return false;
581         }
582         if (mIsFirstEventInSeries != other.mIsFirstEventInSeries) {
583             return false;
584         }
585         if (mOriginalEnd != other.mOriginalEnd) {
586             return false;
587         }
588 
589         if (mOriginalStart != other.mOriginalStart) {
590             return false;
591         }
592         if (mStart != other.mStart) {
593             return false;
594         }
595 
596         if (mOriginalId != other.mOriginalId) {
597             return false;
598         }
599 
600         if (mOriginalSyncId == null) {
601             if (other.mOriginalSyncId != null) {
602                 return false;
603             }
604         } else if (!mOriginalSyncId.equals(other.mOriginalSyncId)) {
605             return false;
606         }
607 
608         if (mRrule == null) {
609             if (other.mRrule != null) {
610                 return false;
611             }
612         } else if (!mRrule.equals(other.mRrule)) {
613             return false;
614         }
615         return true;
616     }
617 
618     /**
619      * Whether the event has been modified based on its original model.
620      *
621      * @param originalModel
622      * @return true if the model is unchanged, false otherwise
623      */
isUnchanged(CalendarEventModel originalModel)624     public boolean isUnchanged(CalendarEventModel originalModel) {
625         if (this == originalModel) {
626             return true;
627         }
628         if (originalModel == null) {
629             return false;
630         }
631 
632         if (!checkOriginalModelFields(originalModel)) {
633             return false;
634         }
635 
636         if (TextUtils.isEmpty(mLocation)) {
637             if (!TextUtils.isEmpty(originalModel.mLocation)) {
638                 return false;
639             }
640         } else if (!mLocation.equals(originalModel.mLocation)) {
641             return false;
642         }
643 
644         if (TextUtils.isEmpty(mTitle)) {
645             if (!TextUtils.isEmpty(originalModel.mTitle)) {
646                 return false;
647             }
648         } else if (!mTitle.equals(originalModel.mTitle)) {
649             return false;
650         }
651 
652         if (TextUtils.isEmpty(mDescription)) {
653             if (!TextUtils.isEmpty(originalModel.mDescription)) {
654                 return false;
655             }
656         } else if (!mDescription.equals(originalModel.mDescription)) {
657             return false;
658         }
659 
660         if (TextUtils.isEmpty(mDuration)) {
661             if (!TextUtils.isEmpty(originalModel.mDuration)) {
662                 return false;
663             }
664         } else if (!mDuration.equals(originalModel.mDuration)) {
665             return false;
666         }
667 
668         if (mEnd != mOriginalEnd) {
669             return false;
670         }
671         if (mStart != mOriginalStart) {
672             return false;
673         }
674 
675         // If this changed the original id and it's not just an exception to the
676         // original event
677         if (mOriginalId != originalModel.mOriginalId && mOriginalId != originalModel.mId) {
678             return false;
679         }
680 
681         if (TextUtils.isEmpty(mRrule)) {
682             // if the rrule is no longer empty check if this is an exception
683             if (!TextUtils.isEmpty(originalModel.mRrule)) {
684                 boolean syncIdNotReferenced = mOriginalSyncId == null
685                         || !mOriginalSyncId.equals(originalModel.mSyncId);
686                 boolean localIdNotReferenced = mOriginalId == -1
687                         || !(mOriginalId == originalModel.mId);
688                 if (syncIdNotReferenced && localIdNotReferenced) {
689                     return false;
690                 }
691             }
692         } else if (!mRrule.equals(originalModel.mRrule)) {
693             return false;
694         }
695 
696         return true;
697     }
698 
699     /**
700      * Checks against an original model for changes to an event. This covers all
701      * the fields that should remain consistent between an original event model
702      * and the new one if nothing in the event was modified. This is also the
703      * portion that overlaps with equality between two event models.
704      *
705      * @param originalModel
706      * @return true if these fields are unchanged, false otherwise
707      */
checkOriginalModelFields(CalendarEventModel originalModel)708     protected boolean checkOriginalModelFields(CalendarEventModel originalModel) {
709         if (mAllDay != originalModel.mAllDay) {
710             return false;
711         }
712         if (mAttendeesList == null) {
713             if (originalModel.mAttendeesList != null) {
714                 return false;
715             }
716         } else if (!mAttendeesList.equals(originalModel.mAttendeesList)) {
717             return false;
718         }
719 
720         if (mCalendarId != originalModel.mCalendarId) {
721             return false;
722         }
723         if (mCalendarColor != originalModel.mCalendarColor) {
724             return false;
725         }
726         if (mCalendarColorInitialized != originalModel.mCalendarColorInitialized) {
727             return false;
728         }
729         if (mGuestsCanInviteOthers != originalModel.mGuestsCanInviteOthers) {
730             return false;
731         }
732         if (mGuestsCanModify != originalModel.mGuestsCanModify) {
733             return false;
734         }
735         if (mGuestsCanSeeGuests != originalModel.mGuestsCanSeeGuests) {
736             return false;
737         }
738         if (mOrganizerCanRespond != originalModel.mOrganizerCanRespond) {
739             return false;
740         }
741         if (mCalendarAccessLevel != originalModel.mCalendarAccessLevel) {
742             return false;
743         }
744         if (mModelUpdatedWithEventCursor != originalModel.mModelUpdatedWithEventCursor) {
745             return false;
746         }
747         if (mHasAlarm != originalModel.mHasAlarm) {
748             return false;
749         }
750         if (mHasAttendeeData != originalModel.mHasAttendeeData) {
751             return false;
752         }
753         if (mId != originalModel.mId) {
754             return false;
755         }
756         if (mIsOrganizer != originalModel.mIsOrganizer) {
757             return false;
758         }
759 
760         if (mOrganizer == null) {
761             if (originalModel.mOrganizer != null) {
762                 return false;
763             }
764         } else if (!mOrganizer.equals(originalModel.mOrganizer)) {
765             return false;
766         }
767 
768         if (mOriginalAllDay == null) {
769             if (originalModel.mOriginalAllDay != null) {
770                 return false;
771             }
772         } else if (!mOriginalAllDay.equals(originalModel.mOriginalAllDay)) {
773             return false;
774         }
775 
776         if (mOriginalTime == null) {
777             if (originalModel.mOriginalTime != null) {
778                 return false;
779             }
780         } else if (!mOriginalTime.equals(originalModel.mOriginalTime)) {
781             return false;
782         }
783 
784         if (mOwnerAccount == null) {
785             if (originalModel.mOwnerAccount != null) {
786                 return false;
787             }
788         } else if (!mOwnerAccount.equals(originalModel.mOwnerAccount)) {
789             return false;
790         }
791 
792         if (mReminders == null) {
793             if (originalModel.mReminders != null) {
794                 return false;
795             }
796         } else if (!mReminders.equals(originalModel.mReminders)) {
797             return false;
798         }
799 
800         if (mSelfAttendeeStatus != originalModel.mSelfAttendeeStatus) {
801             return false;
802         }
803         if (mOwnerAttendeeId != originalModel.mOwnerAttendeeId) {
804             return false;
805         }
806         if (mSyncAccount == null) {
807             if (originalModel.mSyncAccount != null) {
808                 return false;
809             }
810         } else if (!mSyncAccount.equals(originalModel.mSyncAccount)) {
811             return false;
812         }
813 
814         if (mSyncAccountType == null) {
815             if (originalModel.mSyncAccountType != null) {
816                 return false;
817             }
818         } else if (!mSyncAccountType.equals(originalModel.mSyncAccountType)) {
819             return false;
820         }
821 
822         if (mSyncId == null) {
823             if (originalModel.mSyncId != null) {
824                 return false;
825             }
826         } else if (!mSyncId.equals(originalModel.mSyncId)) {
827             return false;
828         }
829 
830         if (mTimezone == null) {
831             if (originalModel.mTimezone != null) {
832                 return false;
833             }
834         } else if (!mTimezone.equals(originalModel.mTimezone)) {
835             return false;
836         }
837 
838         if (mTimezone2 == null) {
839             if (originalModel.mTimezone2 != null) {
840                 return false;
841             }
842         } else if (!mTimezone2.equals(originalModel.mTimezone2)) {
843             return false;
844         }
845 
846         if (mAvailability != originalModel.mAvailability) {
847             return false;
848         }
849 
850         if (mUri == null) {
851             if (originalModel.mUri != null) {
852                 return false;
853             }
854         } else if (!mUri.equals(originalModel.mUri)) {
855             return false;
856         }
857 
858         if (mAccessLevel != originalModel.mAccessLevel) {
859             return false;
860         }
861 
862         if (mEventStatus != originalModel.mEventStatus) {
863             return false;
864         }
865 
866         if (mEventColor != originalModel.mEventColor) {
867             return false;
868         }
869 
870         if (mEventColorInitialized != originalModel.mEventColorInitialized) {
871             return false;
872         }
873 
874         return true;
875     }
876 
877     /**
878      * Sort and uniquify mReminderMinutes.
879      *
880      * @return true (for convenience of caller)
881      */
normalizeReminders()882     public boolean normalizeReminders() {
883         if (mReminders.size() <= 1) {
884             return true;
885         }
886 
887         // sort
888         Collections.sort(mReminders);
889 
890         // remove duplicates
891         ReminderEntry prev = mReminders.get(mReminders.size()-1);
892         for (int i = mReminders.size()-2; i >= 0; --i) {
893             ReminderEntry cur = mReminders.get(i);
894             if (prev.equals(cur)) {
895                 // match, remove later entry
896                 mReminders.remove(i+1);
897             }
898             prev = cur;
899         }
900 
901         return true;
902     }
903 
isCalendarColorInitialized()904     public boolean isCalendarColorInitialized() {
905         return mCalendarColorInitialized;
906     }
907 
isEventColorInitialized()908     public boolean isEventColorInitialized() {
909         return mEventColorInitialized;
910     }
911 
getCalendarColor()912     public int getCalendarColor() {
913         return mCalendarColor;
914     }
915 
getEventColor()916     public int getEventColor() {
917         return mEventColor;
918     }
919 
setCalendarColor(int color)920     public void setCalendarColor(int color) {
921         mCalendarColor = color;
922         mCalendarColorInitialized = true;
923     }
924 
setEventColor(int color)925     public void setEventColor(int color) {
926         mEventColor = color;
927         mEventColorInitialized = true;
928     }
929 
getCalendarEventColors()930     public int[] getCalendarEventColors() {
931         if (mEventColorCache != null) {
932             return mEventColorCache.getColorArray(mCalendarAccountName, mCalendarAccountType);
933         }
934         return null;
935     }
936 
getEventColorKey()937     public int getEventColorKey() {
938         if (mEventColorCache != null) {
939             return mEventColorCache.getColorKey(mCalendarAccountName, mCalendarAccountType,
940                     mEventColor);
941         }
942         return -1;
943     }
944 }
945