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