blob: 8f6507e00b6c27a8172586a965a7fa7d9411221a [file] [log] [blame]
Erik73714162010-05-17 10:43:58 -07001/*
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
Erik6ae7d692010-05-28 11:19:23 -070019import android.content.Context;
20import android.content.Intent;
21import android.content.SharedPreferences;
RoboErika7c03902011-06-14 11:06:44 -070022import android.provider.CalendarContract.Attendees;
23import android.provider.CalendarContract.Calendars;
24import android.provider.CalendarContract.Events;
25import android.provider.CalendarContract.Reminders;
Erik73714162010-05-17 10:43:58 -070026import android.text.TextUtils;
Mindy Pereira18cabd22011-06-09 18:31:23 -070027import android.text.util.Rfc822Token;
Erik73714162010-05-17 10:43:58 -070028
James Kung4afba182012-12-18 23:12:08 -080029import com.android.calendar.event.EditEventHelper;
30import com.android.calendar.event.EventColorCache;
31import com.android.common.Rfc822Validator;
32
Erik59ead672010-11-29 15:47:08 -080033import java.io.Serializable;
Erik73714162010-05-17 10:43:58 -070034import java.util.ArrayList;
Andy McFaddenfea9af52011-05-13 15:40:10 -070035import java.util.Collections;
Erikd845fbe2010-08-12 11:20:01 -070036import java.util.LinkedHashMap;
Mindy Pereira18cabd22011-06-09 18:31:23 -070037import java.util.LinkedHashSet;
Erik6ae7d692010-05-28 11:19:23 -070038import java.util.TimeZone;
Erik73714162010-05-17 10:43:58 -070039
40/**
41 * Stores all the information needed to fill out an entry in the events table.
Erikeca82e92010-06-11 14:05:00 -070042 * 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.
Erik73714162010-05-17 10:43:58 -070044 */
Erik59ead672010-11-29 15:47:08 -080045public class CalendarEventModel implements Serializable {
Andy McFaddenae5bcce2011-04-14 09:28:08 -070046 private static final String TAG = "CalendarEventModel";
47
Erik59ead672010-11-29 15:47:08 -080048 public static class Attendee implements Serializable {
Erikd845fbe2010-08-12 11:20:01 -070049 @Override
50 public int hashCode() {
51 return (mEmail == null) ? 0 : mEmail.hashCode();
52 }
53
54 @Override
55 public boolean equals(Object obj) {
56 if (this == obj) {
57 return true;
58 }
Erikd845fbe2010-08-12 11:20:01 -070059 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
Isaac Katzenelson016d5762011-05-23 16:05:51 -070069 String getDisplayName() {
70 if (TextUtils.isEmpty(mName)) {
71 return mEmail;
72 } else {
73 return mName;
74 }
75 }
76
Erikd845fbe2010-08-12 11:20:01 -070077 public String mName;
78 public String mEmail;
79 public int mStatus;
Sara Tingddbc0022012-04-26 17:08:46 -070080 public String mIdentity;
81 public String mIdNamespace;
Erikd845fbe2010-08-12 11:20:01 -070082
83 public Attendee(String name, String email) {
Sara Tingddbc0022012-04-26 17:08:46 -070084 this(name, email, Attendees.ATTENDEE_STATUS_NONE, null, null);
Erikd845fbe2010-08-12 11:20:01 -070085 }
Sara Tingddbc0022012-04-26 17:08:46 -070086 public Attendee(String name, String email, int status, String identity,
87 String idNamespace) {
Isaac Katzenelson667af282011-06-02 12:49:54 -070088 mName = name;
89 mEmail = email;
90 mStatus = status;
Sara Tingddbc0022012-04-26 17:08:46 -070091 mIdentity = identity;
92 mIdNamespace = idNamespace;
Isaac Katzenelson667af282011-06-02 12:49:54 -070093 }
Erikd845fbe2010-08-12 11:20:01 -070094 }
95
Andy McFaddenfea9af52011-05-13 15:40:10 -070096 /**
97 * A single reminder entry.
98 *
99 * Instances of the class are immutable.
100 */
Andy McFaddenc27e56f2011-05-16 13:35:54 -0700101 public static class ReminderEntry implements Comparable<ReminderEntry>, Serializable {
Andy McFaddenfea9af52011-05-13 15:40:10 -0700102 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 */
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 */
Andy McFadden9645d9c2011-05-16 15:28:15 -0700121 public static ReminderEntry valueOf(int minutes) {
Andy McFaddenfea9af52011-05-13 15:40:10 -0700122 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 */
131 private ReminderEntry(int minutes, int method) {
132 // TODO: error-check args
133 mMinutes = minutes;
134 mMethod = method;
135 }
136
137 @Override
138 public int hashCode() {
139 return mMinutes * 10 + mMethod;
140 }
141
142 @Override
143 public boolean equals(Object obj) {
Andy McFadden9645d9c2011-05-16 15:28:15 -0700144 if (this == obj) {
Andy McFaddenfea9af52011-05-13 15:40:10 -0700145 return true;
Andy McFadden9645d9c2011-05-16 15:28:15 -0700146 }
Andy McFaddenfea9af52011-05-13 15:40:10 -0700147 if (!(obj instanceof ReminderEntry)) {
148 return false;
149 }
150
151 ReminderEntry re = (ReminderEntry) obj;
152
Andy McFadden9645d9c2011-05-16 15:28:15 -0700153 if (re.mMinutes != mMinutes) {
Andy McFaddenfea9af52011-05-13 15:40:10 -0700154 return false;
Andy McFadden9645d9c2011-05-16 15:28:15 -0700155 }
Andy McFaddenfea9af52011-05-13 15:40:10 -0700156
Andy McFadden9645d9c2011-05-16 15:28:15 -0700157 // 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.
Andy McFaddenfea9af52011-05-13 15:40:10 -0700160 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
166 public String toString() {
167 return "ReminderEntry min=" + mMinutes + " meth=" + mMethod;
168 }
169
Andy McFaddenc27e56f2011-05-16 13:35:54 -0700170 /**
Andy McFadden9645d9c2011-05-16 15:28:15 -0700171 * Comparison function for a sort ordered primarily descending by minutes,
172 * secondarily ascending by method type.
Andy McFaddenc27e56f2011-05-16 13:35:54 -0700173 */
Michael Chanf9fa0ab2012-12-14 00:41:18 -0800174 @Override
Andy McFaddenfea9af52011-05-13 15:40:10 -0700175 public int compareTo(ReminderEntry re) {
176 if (re.mMinutes != mMinutes) {
177 return re.mMinutes - mMinutes;
178 }
179 if (re.mMethod != mMethod) {
Andy McFadden9645d9c2011-05-16 15:28:15 -0700180 return mMethod - re.mMethod;
Andy McFaddenfea9af52011-05-13 15:40:10 -0700181 }
182 return 0;
183 }
184
185 /** Returns the minutes. */
186 public int getMinutes() {
187 return mMinutes;
188 }
189
190 /** Returns the alert method. */
191 public int getMethod() {
192 return mMethod;
193 }
194 }
195
Erik73714162010-05-17 10:43:58 -0700196 // TODO strip out fields that don't ever get used
Erik6ae7d692010-05-28 11:19:23 -0700197 /**
198 * The uri of the event in the db. This should only be null for new events.
199 */
Erik59ead672010-11-29 15:47:08 -0800200 public String mUri = null;
Erikeca82e92010-06-11 14:05:00 -0700201 public long mId = -1;
202 public long mCalendarId = -1;
Michael Chan9d5f3512010-11-05 16:23:57 -0700203 public String mCalendarDisplayName = ""; // Make sure this is in sync with the mCalendarId
James Kungf56b1492013-03-07 15:10:13 -0800204 private int mCalendarColor = -1;
205 private boolean mCalendarColorInitialized = false;
James Kung4afba182012-12-18 23:12:08 -0800206 public String mCalendarAccountName;
207 public String mCalendarAccountType;
Andy McFadden9645d9c2011-05-16 15:28:15 -0700208 public int mCalendarMaxReminders;
209 public String mCalendarAllowedReminders;
RoboErikc6680c52011-10-28 13:57:54 -0700210 public String mCalendarAllowedAttendeeTypes;
211 public String mCalendarAllowedAvailability;
Michael Chan9d5f3512010-11-05 16:23:57 -0700212
Erik73714162010-05-17 10:43:58 -0700213 public String mSyncId = null;
214 public String mSyncAccount = null;
215 public String mSyncAccountType = null;
Erikeca82e92010-06-11 14:05:00 -0700216
James Kung4afba182012-12-18 23:12:08 -0800217 public EventColorCache mEventColorCache;
James Kungf56b1492013-03-07 15:10:13 -0800218 private int mEventColor = -1;
219 private boolean mEventColorInitialized = false;
James Kung4afba182012-12-18 23:12:08 -0800220
Erik73714162010-05-17 10:43:58 -0700221 // PROVIDER_NOTES owner account comes from the calendars table
222 public String mOwnerAccount = null;
Erik73714162010-05-17 10:43:58 -0700223 public String mTitle = null;
224 public String mLocation = null;
225 public String mDescription = null;
226 public String mRrule = null;
227 public String mOrganizer = null;
Michael Chan352e1a22010-09-28 05:15:08 -0700228 public String mOrganizerDisplayName = null;
229 /**
230 * Read-Only - Derived from other fields
231 */
Erikeca82e92010-06-11 14:05:00 -0700232 public boolean mIsOrganizer = true;
Erik73714162010-05-17 10:43:58 -0700233 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;
Erikeca82e92010-06-11 14:05:00 -0700239
Erik73714162010-05-17 10:43:58 -0700240 // 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;
RoboErikc6680c52011-10-28 13:57:54 -0700249 public int mAvailability = Events.AVAILABILITY_BUSY;
Erik73714162010-05-17 10:43:58 -0700250
251 // PROVIDER_NOTES How does an event not have attendee data? The owner is added
252 // as an attendee by default.
Erik6ae7d692010-05-28 11:19:23 -0700253 public boolean mHasAttendeeData = true;
Erik73714162010-05-17 10:43:58 -0700254 public int mSelfAttendeeStatus = -1;
Erikd845fbe2010-08-12 11:20:01 -0700255 public int mOwnerAttendeeId = -1;
RoboErik28dab652011-07-21 15:08:39 -0700256 public String mOriginalSyncId = null;
257 public long mOriginalId = -1;
Erik73714162010-05-17 10:43:58 -0700258 public Long mOriginalTime = null;
259 public Boolean mOriginalAllDay = null;
Erik73714162010-05-17 10:43:58 -0700260 public boolean mGuestsCanModify = false;
261 public boolean mGuestsCanInviteOthers = false;
262 public boolean mGuestsCanSeeGuests = false;
Erik73714162010-05-17 10:43:58 -0700263
Michael Chan352e1a22010-09-28 05:15:08 -0700264 public boolean mOrganizerCanRespond = false;
RoboErikef2add92011-06-09 14:49:53 -0700265 public int mCalendarAccessLevel = Calendars.CAL_ACCESS_CONTRIBUTOR;
Michael Chan352e1a22010-09-28 05:15:08 -0700266
Michael Chane3f85db2012-04-26 16:28:42 -0700267 public int mEventStatus = Events.STATUS_CONFIRMED;
268
Michael Chan352e1a22010-09-28 05:15:08 -0700269 // The model can't be updated with a calendar cursor until it has been
270 // updated with an event cursor.
271 public boolean mModelUpdatedWithEventCursor;
Michael Chan352e1a22010-09-28 05:15:08 -0700272
Michael Chanced0eb62011-05-31 18:12:52 -0700273 public int mAccessLevel = 0;
Andy McFaddenfea9af52011-05-13 15:40:10 -0700274 public ArrayList<ReminderEntry> mReminders;
Andy McFadden9645d9c2011-05-16 15:28:15 -0700275 public ArrayList<ReminderEntry> mDefaultReminders;
Erikeca82e92010-06-11 14:05:00 -0700276
Erik73714162010-05-17 10:43:58 -0700277 // 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?
Erikd845fbe2010-08-12 11:20:01 -0700279 public LinkedHashMap<String, Attendee> mAttendeesList;
Erik73714162010-05-17 10:43:58 -0700280
281 public CalendarEventModel() {
Andy McFaddenfea9af52011-05-13 15:40:10 -0700282 mReminders = new ArrayList<ReminderEntry>();
Andy McFadden9645d9c2011-05-16 15:28:15 -0700283 mDefaultReminders = new ArrayList<ReminderEntry>();
Erikd845fbe2010-08-12 11:20:01 -0700284 mAttendeesList = new LinkedHashMap<String, Attendee>();
Erik6ae7d692010-05-28 11:19:23 -0700285 mTimezone = TimeZone.getDefault().getID();
Erik73714162010-05-17 10:43:58 -0700286 }
287
Erik6ae7d692010-05-28 11:19:23 -0700288 public CalendarEventModel(Context context) {
289 this();
290
Erik8a548962011-01-10 18:08:03 -0800291 mTimezone = Utils.getTimeZone(context, null);
Daisuke Miyakawa4b441bd2010-09-16 14:55:36 -0700292 SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
Michael Chan9d8a3762011-03-29 15:40:24 -0700293
294 String defaultReminder = prefs.getString(
295 GeneralPreferences.KEY_DEFAULT_REMINDER, GeneralPreferences.NO_REMINDER_STRING);
Erik6ae7d692010-05-28 11:19:23 -0700296 int defaultReminderMins = Integer.parseInt(defaultReminder);
Michael Chan9d8a3762011-03-29 15:40:24 -0700297 if (defaultReminderMins != GeneralPreferences.NO_REMINDER) {
Andy McFadden9645d9c2011-05-16 15:28:15 -0700298 // Assume all calendars allow at least one reminder.
Erik6ae7d692010-05-28 11:19:23 -0700299 mHasAlarm = true;
Andy McFaddenfea9af52011-05-13 15:40:10 -0700300 mReminders.add(ReminderEntry.valueOf(defaultReminderMins));
Andy McFadden9645d9c2011-05-16 15:28:15 -0700301 mDefaultReminders.add(ReminderEntry.valueOf(defaultReminderMins));
Erik6ae7d692010-05-28 11:19:23 -0700302 }
303 }
304
305 public CalendarEventModel(Context context, Intent intent) {
306 this(context);
307
Michael Chanc250e2e2011-05-23 12:52:50 -0700308 if (intent == null) {
309 return;
310 }
311
Erik6ae7d692010-05-28 11:19:23 -0700312 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
Michael Chanced0eb62011-05-31 18:12:52 -0700327 int availability = intent.getIntExtra(Events.AVAILABILITY, -1);
328 if (availability != -1) {
RoboErikc6680c52011-10-28 13:57:54 -0700329 mAvailability = availability;
Erik6ae7d692010-05-28 11:19:23 -0700330 }
331
Michael Chanced0eb62011-05-31 18:12:52 -0700332 int accessLevel = intent.getIntExtra(Events.ACCESS_LEVEL, -1);
333 if (accessLevel != -1) {
RoboErik510e5ab2011-10-17 11:28:46 -0700334 if (accessLevel > 0) {
335 // TODO remove this if we add support for
336 // Events.ACCESS_CONFIDENTIAL
337 accessLevel--;
338 }
Michael Chanced0eb62011-05-31 18:12:52 -0700339 mAccessLevel = accessLevel;
Erik6ae7d692010-05-28 11:19:23 -0700340 }
341
342 String rrule = intent.getStringExtra(Events.RRULE);
Michael Chan66b20672010-12-20 13:50:28 -0800343 if (!TextUtils.isEmpty(rrule)) {
Erik6ae7d692010-05-28 11:19:23 -0700344 mRrule = rrule;
345 }
Michael Chanc250e2e2011-05-23 12:52:50 -0700346
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 }
Erik6ae7d692010-05-28 11:19:23 -0700359 }
360
Erik73714162010-05-17 10:43:58 -0700361 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
Michael Chanf9fa0ab2012-12-14 00:41:18 -0800371 public boolean isEmpty() {
372 if (mTitle != null && mTitle.trim().length() > 0) {
Erik73714162010-05-17 10:43:58 -0700373 return false;
374 }
375
Michael Chanf9fa0ab2012-12-14 00:41:18 -0800376 if (mLocation != null && mLocation.trim().length() > 0) {
Erik73714162010-05-17 10:43:58 -0700377 return false;
378 }
379
Michael Chanf9fa0ab2012-12-14 00:41:18 -0800380 if (mDescription != null && mDescription.trim().length() > 0) {
Erik73714162010-05-17 10:43:58 -0700381 return false;
382 }
383
384 return true;
385 }
386
387 public void clear() {
388 mUri = null;
389 mId = -1;
390 mCalendarId = -1;
James Kungf56b1492013-03-07 15:10:13 -0800391 mCalendarColor = -1;
392 mCalendarColorInitialized = false;
393
394 mEventColorCache = null;
395 mEventColor = -1;
396 mEventColorInitialized = false;
Erik73714162010-05-17 10:43:58 -0700397
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;
Michael Chan352e1a22010-09-28 05:15:08 -0700408 mOrganizerDisplayName = null;
Erikeca82e92010-06-11 14:05:00 -0700409 mIsOrganizer = true;
Erik73714162010-05-17 10:43:58 -0700410 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
Erik6ae7d692010-05-28 11:19:23 -0700422 mHasAttendeeData = true;
Erik73714162010-05-17 10:43:58 -0700423 mSelfAttendeeStatus = -1;
Erikd845fbe2010-08-12 11:20:01 -0700424 mOwnerAttendeeId = -1;
RoboErik28dab652011-07-21 15:08:39 -0700425 mOriginalId = -1;
426 mOriginalSyncId = null;
Erik73714162010-05-17 10:43:58 -0700427 mOriginalTime = null;
428 mOriginalAllDay = null;
429
430 mGuestsCanModify = false;
431 mGuestsCanInviteOthers = false;
432 mGuestsCanSeeGuests = false;
Michael Chanced0eb62011-05-31 18:12:52 -0700433 mAccessLevel = 0;
Michael Chane3f85db2012-04-26 16:28:42 -0700434 mEventStatus = Events.STATUS_CONFIRMED;
Michael Chan304bf0d2010-10-13 14:04:56 -0700435 mOrganizerCanRespond = false;
RoboErikef2add92011-06-09 14:49:53 -0700436 mCalendarAccessLevel = Calendars.CAL_ACCESS_CONTRIBUTOR;
Michael Chan304bf0d2010-10-13 14:04:56 -0700437 mModelUpdatedWithEventCursor = false;
RoboErikc6680c52011-10-28 13:57:54 -0700438 mCalendarAllowedReminders = null;
439 mCalendarAllowedAttendeeTypes = null;
440 mCalendarAllowedAvailability = null;
Erik73714162010-05-17 10:43:58 -0700441
Andy McFaddenfea9af52011-05-13 15:40:10 -0700442 mReminders = new ArrayList<ReminderEntry>();
Erikd845fbe2010-08-12 11:20:01 -0700443 mAttendeesList.clear();
444 }
445
446 public void addAttendee(Attendee attendee) {
447 mAttendeesList.put(attendee.mEmail, attendee);
448 }
449
Mindy Pereira18cabd22011-06-09 18:31:23 -0700450 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
Erikd845fbe2010-08-12 11:20:01 -0700464 public void removeAttendee(Attendee attendee) {
465 mAttendeesList.remove(attendee.mEmail);
466 }
467
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();
Erik73714162010-05-17 10:43:58 -0700479 }
480
481 @Override
482 public int hashCode() {
483 final int prime = 31;
484 int result = 1;
485 result = prime * result + (mAllDay ? 1231 : 1237);
Erikd845fbe2010-08-12 11:20:01 -0700486 result = prime * result + ((mAttendeesList == null) ? 0 : getAttendeesString().hashCode());
Erikeca82e92010-06-11 14:05:00 -0700487 result = prime * result + (int) (mCalendarId ^ (mCalendarId >>> 32));
Erik73714162010-05-17 10:43:58 -0700488 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);
Michael Chan304bf0d2010-10-13 14:04:56 -0700494 result = prime * result + (mOrganizerCanRespond ? 1231 : 1237);
495 result = prime * result + (mModelUpdatedWithEventCursor ? 1231 : 1237);
496 result = prime * result + mCalendarAccessLevel;
Erik73714162010-05-17 10:43:58 -0700497 result = prime * result + (mHasAlarm ? 1231 : 1237);
498 result = prime * result + (mHasAttendeeData ? 1231 : 1237);
Erikeca82e92010-06-11 14:05:00 -0700499 result = prime * result + (int) (mId ^ (mId >>> 32));
Erik73714162010-05-17 10:43:58 -0700500 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));
RoboErik28dab652011-07-21 15:08:39 -0700506 result = prime * result + ((mOriginalSyncId == null) ? 0 : mOriginalSyncId.hashCode());
507 result = prime * result + (int) (mOriginalId ^ (mOriginalEnd >>> 32));
Erik73714162010-05-17 10:43:58 -0700508 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());
Andy McFaddenfea9af52011-05-13 15:40:10 -0700511 result = prime * result + ((mReminders == null) ? 0 : mReminders.hashCode());
Erik73714162010-05-17 10:43:58 -0700512 result = prime * result + ((mRrule == null) ? 0 : mRrule.hashCode());
513 result = prime * result + mSelfAttendeeStatus;
Erikd845fbe2010-08-12 11:20:01 -0700514 result = prime * result + mOwnerAttendeeId;
Erik73714162010-05-17 10:43:58 -0700515 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());
RoboErikc6680c52011-10-28 13:57:54 -0700522 result = prime * result + (mAvailability);
Erik73714162010-05-17 10:43:58 -0700523 result = prime * result + ((mUri == null) ? 0 : mUri.hashCode());
Michael Chanced0eb62011-05-31 18:12:52 -0700524 result = prime * result + mAccessLevel;
Michael Chane3f85db2012-04-26 16:28:42 -0700525 result = prime * result + mEventStatus;
Erik73714162010-05-17 10:43:58 -0700526 return result;
527 }
528
529 // Autogenerated equals method
530 @Override
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;
Erika7694ee2010-12-07 15:46:18 -0800543 if (!checkOriginalModelFields(other)) {
Erik73714162010-05-17 10:43:58 -0700544 return false;
545 }
546
RoboErik28dab652011-07-21 15:08:39 -0700547 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
Erik73714162010-05-17 10:43:58 -0700579 if (mEnd != other.mEnd) {
580 return false;
581 }
Erik73714162010-05-17 10:43:58 -0700582 if (mIsFirstEventInSeries != other.mIsFirstEventInSeries) {
583 return false;
584 }
Erik73714162010-05-17 10:43:58 -0700585 if (mOriginalEnd != other.mOriginalEnd) {
586 return false;
587 }
588
Erik73714162010-05-17 10:43:58 -0700589 if (mOriginalStart != other.mOriginalStart) {
590 return false;
591 }
Erika7694ee2010-12-07 15:46:18 -0800592 if (mStart != other.mStart) {
593 return false;
594 }
Erik31eb9e32010-12-08 15:52:06 -0800595
RoboErik28dab652011-07-21 15:08:39 -0700596 if (mOriginalId != other.mOriginalId) {
597 return false;
598 }
599
600 if (mOriginalSyncId == null) {
601 if (other.mOriginalSyncId != null) {
Erik31eb9e32010-12-08 15:52:06 -0800602 return false;
603 }
RoboErik28dab652011-07-21 15:08:39 -0700604 } else if (!mOriginalSyncId.equals(other.mOriginalSyncId)) {
Erik31eb9e32010-12-08 15:52:06 -0800605 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 }
Erika7694ee2010-12-07 15:46:18 -0800615 return true;
616 }
Erik73714162010-05-17 10:43:58 -0700617
Erika7694ee2010-12-07 15:46:18 -0800618 /**
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 */
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 }
RoboErik28dab652011-07-21 15:08:39 -0700635
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
Erika7694ee2010-12-07 15:46:18 -0800668 if (mEnd != mOriginalEnd) {
669 return false;
670 }
671 if (mStart != mOriginalStart) {
672 return false;
673 }
674
RoboErik28dab652011-07-21 15:08:39 -0700675 // 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) {
Erik31eb9e32010-12-08 15:52:06 -0800689 return false;
690 }
691 }
692 } else if (!mRrule.equals(originalModel.mRrule)) {
693 return false;
694 }
695
Erika7694ee2010-12-07 15:46:18 -0800696 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 */
708 protected boolean checkOriginalModelFields(CalendarEventModel originalModel) {
709 if (mAllDay != originalModel.mAllDay) {
710 return false;
711 }
712 if (mAttendeesList == null) {
713 if (originalModel.mAttendeesList != null) {
Erik73714162010-05-17 10:43:58 -0700714 return false;
715 }
Michael Chand0fb2dd2011-01-07 14:37:18 -0800716 } else if (!mAttendeesList.equals(originalModel.mAttendeesList)) {
Erika7694ee2010-12-07 15:46:18 -0800717 return false;
718 }
719
720 if (mCalendarId != originalModel.mCalendarId) {
721 return false;
722 }
James Kungf56b1492013-03-07 15:10:13 -0800723 if (mCalendarColor != originalModel.mCalendarColor) {
724 return false;
725 }
726 if (mCalendarColorInitialized != originalModel.mCalendarColorInitialized) {
727 return false;
728 }
Erika7694ee2010-12-07 15:46:18 -0800729 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
Erika7694ee2010-12-07 15:46:18 -0800760 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
Erika7694ee2010-12-07 15:46:18 -0800776 if (mOriginalTime == null) {
777 if (originalModel.mOriginalTime != null) {
778 return false;
779 }
780 } else if (!mOriginalTime.equals(originalModel.mOriginalTime)) {
Erik73714162010-05-17 10:43:58 -0700781 return false;
782 }
783
784 if (mOwnerAccount == null) {
Erika7694ee2010-12-07 15:46:18 -0800785 if (originalModel.mOwnerAccount != null) {
Erik73714162010-05-17 10:43:58 -0700786 return false;
787 }
Erika7694ee2010-12-07 15:46:18 -0800788 } else if (!mOwnerAccount.equals(originalModel.mOwnerAccount)) {
Erik73714162010-05-17 10:43:58 -0700789 return false;
790 }
791
Andy McFaddenfea9af52011-05-13 15:40:10 -0700792 if (mReminders == null) {
793 if (originalModel.mReminders != null) {
Erik73714162010-05-17 10:43:58 -0700794 return false;
795 }
Andy McFaddenfea9af52011-05-13 15:40:10 -0700796 } else if (!mReminders.equals(originalModel.mReminders)) {
Erik73714162010-05-17 10:43:58 -0700797 return false;
798 }
799
Erika7694ee2010-12-07 15:46:18 -0800800 if (mSelfAttendeeStatus != originalModel.mSelfAttendeeStatus) {
Erik73714162010-05-17 10:43:58 -0700801 return false;
802 }
Erika7694ee2010-12-07 15:46:18 -0800803 if (mOwnerAttendeeId != originalModel.mOwnerAttendeeId) {
Erik73714162010-05-17 10:43:58 -0700804 return false;
805 }
806 if (mSyncAccount == null) {
Erika7694ee2010-12-07 15:46:18 -0800807 if (originalModel.mSyncAccount != null) {
Erik73714162010-05-17 10:43:58 -0700808 return false;
809 }
Erika7694ee2010-12-07 15:46:18 -0800810 } else if (!mSyncAccount.equals(originalModel.mSyncAccount)) {
Erik73714162010-05-17 10:43:58 -0700811 return false;
812 }
813
814 if (mSyncAccountType == null) {
Erika7694ee2010-12-07 15:46:18 -0800815 if (originalModel.mSyncAccountType != null) {
Erik73714162010-05-17 10:43:58 -0700816 return false;
817 }
Erika7694ee2010-12-07 15:46:18 -0800818 } else if (!mSyncAccountType.equals(originalModel.mSyncAccountType)) {
Erik73714162010-05-17 10:43:58 -0700819 return false;
820 }
821
822 if (mSyncId == null) {
Erika7694ee2010-12-07 15:46:18 -0800823 if (originalModel.mSyncId != null) {
Erik73714162010-05-17 10:43:58 -0700824 return false;
825 }
Erika7694ee2010-12-07 15:46:18 -0800826 } else if (!mSyncId.equals(originalModel.mSyncId)) {
Erik73714162010-05-17 10:43:58 -0700827 return false;
828 }
829
830 if (mTimezone == null) {
Erika7694ee2010-12-07 15:46:18 -0800831 if (originalModel.mTimezone != null) {
Erik73714162010-05-17 10:43:58 -0700832 return false;
833 }
Erika7694ee2010-12-07 15:46:18 -0800834 } else if (!mTimezone.equals(originalModel.mTimezone)) {
Erik73714162010-05-17 10:43:58 -0700835 return false;
836 }
837
838 if (mTimezone2 == null) {
Erika7694ee2010-12-07 15:46:18 -0800839 if (originalModel.mTimezone2 != null) {
Erik73714162010-05-17 10:43:58 -0700840 return false;
841 }
Erika7694ee2010-12-07 15:46:18 -0800842 } else if (!mTimezone2.equals(originalModel.mTimezone2)) {
Erik73714162010-05-17 10:43:58 -0700843 return false;
844 }
845
Michael Chanced0eb62011-05-31 18:12:52 -0700846 if (mAvailability != originalModel.mAvailability) {
Erik73714162010-05-17 10:43:58 -0700847 return false;
848 }
849
850 if (mUri == null) {
Erika7694ee2010-12-07 15:46:18 -0800851 if (originalModel.mUri != null) {
Erik73714162010-05-17 10:43:58 -0700852 return false;
853 }
Erika7694ee2010-12-07 15:46:18 -0800854 } else if (!mUri.equals(originalModel.mUri)) {
Erik73714162010-05-17 10:43:58 -0700855 return false;
856 }
857
Michael Chanced0eb62011-05-31 18:12:52 -0700858 if (mAccessLevel != originalModel.mAccessLevel) {
Erik73714162010-05-17 10:43:58 -0700859 return false;
860 }
Michael Chane3f85db2012-04-26 16:28:42 -0700861
862 if (mEventStatus != originalModel.mEventStatus) {
863 return false;
864 }
James Kung4afba182012-12-18 23:12:08 -0800865
866 if (mEventColor != originalModel.mEventColor) {
867 return false;
868 }
869
James Kungf56b1492013-03-07 15:10:13 -0800870 if (mEventColorInitialized != originalModel.mEventColorInitialized) {
871 return false;
872 }
873
Erik73714162010-05-17 10:43:58 -0700874 return true;
875 }
Andy McFaddenae5bcce2011-04-14 09:28:08 -0700876
877 /**
878 * Sort and uniquify mReminderMinutes.
879 *
Andy McFaddenfea9af52011-05-13 15:40:10 -0700880 * @return true (for convenience of caller)
Andy McFaddenae5bcce2011-04-14 09:28:08 -0700881 */
882 public boolean normalizeReminders() {
Andy McFaddenfea9af52011-05-13 15:40:10 -0700883 if (mReminders.size() <= 1) {
884 return true;
Andy McFaddenae5bcce2011-04-14 09:28:08 -0700885 }
Andy McFaddenfea9af52011-05-13 15:40:10 -0700886
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
Andy McFaddenae5bcce2011-04-14 09:28:08 -0700901 return true;
902 }
James Kung4afba182012-12-18 23:12:08 -0800903
James Kungf56b1492013-03-07 15:10:13 -0800904 public boolean isCalendarColorInitialized() {
905 return mCalendarColorInitialized;
906 }
907
908 public boolean isEventColorInitialized() {
909 return mEventColorInitialized;
910 }
911
912 public int getCalendarColor() {
913 return mCalendarColor;
914 }
915
916 public int getEventColor() {
917 return mEventColor;
918 }
919
920 public void setCalendarColor(int color) {
921 mCalendarColor = color;
922 mCalendarColorInitialized = true;
923 }
924
925 public void setEventColor(int color) {
926 mEventColor = color;
927 mEventColorInitialized = true;
928 }
929
James Kung4afba182012-12-18 23:12:08 -0800930 public int[] getCalendarEventColors() {
931 if (mEventColorCache != null) {
932 return mEventColorCache.getColorArray(mCalendarAccountName, mCalendarAccountType);
933 }
934 return null;
935 }
936
937 public int getEventColorKey() {
938 if (mEventColorCache != null) {
939 return mEventColorCache.getColorKey(mCalendarAccountName, mCalendarAccountType,
940 mEventColor);
941 }
942 return -1;
943 }
Andy McFaddenfea9af52011-05-13 15:40:10 -0700944}