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