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 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 } 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 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 83 public Attendee(String name, String email) { 84 this(name, email, Attendees.ATTENDEE_STATUS_NONE, null, null); 85 } 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 */ 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 */ 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 */ 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) { 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 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 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. */ 186 public int getMinutes() { 187 return mMinutes; 188 } 189 190 /** Returns the alert method. */ 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 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 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 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 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 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 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 446 public void addAttendee(Attendee attendee) { 447 mAttendeesList.put(attendee.mEmail, attendee); 448 } 449 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 464 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(); 479 } 480 481 @Override 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 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 */ 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 */ 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 */ 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 904 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 930 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 } 944 } 945