EditEventFragment.java revision 6a7003d1b9bf20f4c6e001d054b1ab556ddec4a4
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.calendar.event; 18 19import android.app.Activity; 20import android.app.AlertDialog; 21import android.app.Fragment; 22import android.content.AsyncQueryHandler; 23import android.content.ContentProviderOperation; 24import android.content.ContentResolver; 25import android.content.ContentUris; 26import android.content.ContentValues; 27import android.content.Context; 28import android.content.DialogInterface; 29import android.content.DialogInterface.OnClickListener; 30import android.content.Intent; 31import android.database.Cursor; 32import android.database.MatrixCursor; 33import android.net.Uri; 34import android.os.Bundle; 35import android.provider.CalendarContract.Attendees; 36import android.provider.CalendarContract.Calendars; 37import android.provider.CalendarContract.Events; 38import android.provider.CalendarContract.Reminders; 39import android.text.TextUtils; 40import android.util.Log; 41import android.view.LayoutInflater; 42import android.view.Menu; 43import android.view.MenuInflater; 44import android.view.MenuItem; 45import android.view.View; 46import android.view.ViewGroup; 47import android.view.inputmethod.InputMethodManager; 48import android.widget.Toast; 49 50import com.android.calendar.AsyncQueryService; 51import com.android.calendar.CalendarController; 52import com.android.calendar.CalendarController.EventHandler; 53import com.android.calendar.CalendarController.EventInfo; 54import com.android.calendar.CalendarController.EventType; 55import com.android.calendar.CalendarEventModel; 56import com.android.calendar.CalendarEventModel.Attendee; 57import com.android.calendar.CalendarEventModel.ReminderEntry; 58import com.android.calendar.DeleteEventHelper; 59import com.android.calendar.R; 60import com.android.calendar.Utils; 61 62import java.io.Serializable; 63import java.util.ArrayList; 64import java.util.Collections; 65 66public class EditEventFragment extends Fragment implements EventHandler { 67 private static final String TAG = "EditEventActivity"; 68 69 private static final String BUNDLE_KEY_MODEL = "key_model"; 70 private static final String BUNDLE_KEY_EDIT_STATE = "key_edit_state"; 71 private static final String BUNDLE_KEY_EVENT = "key_event"; 72 private static final String BUNDLE_KEY_READ_ONLY = "key_read_only"; 73 74 private static final boolean DEBUG = false; 75 76 private static final int TOKEN_EVENT = 1; 77 private static final int TOKEN_ATTENDEES = 1 << 1; 78 private static final int TOKEN_REMINDERS = 1 << 2; 79 private static final int TOKEN_CALENDARS = 1 << 3; 80 private static final int TOKEN_ALL = TOKEN_EVENT | TOKEN_ATTENDEES | TOKEN_REMINDERS 81 | TOKEN_CALENDARS; 82 private static final int TOKEN_UNITIALIZED = 1 << 31; 83 84 /** 85 * A bitfield of TOKEN_* to keep track which query hasn't been completed 86 * yet. Once all queries have returned, the model can be applied to the 87 * view. 88 */ 89 private int mOutstandingQueries = TOKEN_UNITIALIZED; 90 91 EditEventHelper mHelper; 92 CalendarEventModel mModel; 93 CalendarEventModel mOriginalModel; 94 CalendarEventModel mRestoreModel; 95 EditEventView mView; 96 QueryHandler mHandler; 97 98 private AlertDialog mModifyDialog; 99 int mModification = Utils.MODIFY_UNINITIALIZED; 100 101 private EventInfo mEvent; 102 private EventBundle mEventBundle; 103 private Uri mUri; 104 private long mBegin; 105 private long mEnd; 106 107 private Activity mContext; 108 private Done mOnDone = new Done(); 109 private Menu mMenu; 110 111 private boolean mSaveOnDetach = true; 112 private boolean mIsReadOnly = false; 113 public boolean mShowModifyDialogOnLaunch = false; 114 115 private InputMethodManager mInputMethodManager; 116 117 private Intent mIntent; 118 119 // TODO turn this into a helper function in EditEventHelper for building the 120 // model 121 private class QueryHandler extends AsyncQueryHandler { 122 public QueryHandler(ContentResolver cr) { 123 super(cr); 124 } 125 126 @Override 127 protected void onQueryComplete(int token, Object cookie, Cursor cursor) { 128 // If the query didn't return a cursor for some reason return 129 if (cursor == null) { 130 return; 131 } 132 133 // If the Activity is finishing, then close the cursor. 134 // Otherwise, use the new cursor in the adapter. 135 final Activity activity = EditEventFragment.this.getActivity(); 136 if (activity == null || activity.isFinishing()) { 137 cursor.close(); 138 return; 139 } 140 long eventId; 141 switch (token) { 142 case TOKEN_EVENT: 143 if (cursor.getCount() == 0) { 144 // The cursor is empty. This can happen if the event 145 // was deleted. 146 cursor.close(); 147 mOnDone.setDoneCode(Utils.DONE_EXIT); 148 mSaveOnDetach = false; 149 mOnDone.run(); 150 return; 151 } 152 mOriginalModel = new CalendarEventModel(); 153 EditEventHelper.setModelFromCursor(mOriginalModel, cursor); 154 EditEventHelper.setModelFromCursor(mModel, cursor); 155 cursor.close(); 156 157 mOriginalModel.mUri = mUri.toString(); 158 159 mModel.mUri = mUri.toString(); 160 mModel.mOriginalStart = mBegin; 161 mModel.mOriginalEnd = mEnd; 162 mModel.mIsFirstEventInSeries = mBegin == mOriginalModel.mStart; 163 mModel.mStart = mBegin; 164 mModel.mEnd = mEnd; 165 166 eventId = mModel.mId; 167 168 // TOKEN_ATTENDEES 169 if (mModel.mHasAttendeeData && eventId != -1) { 170 Uri attUri = Attendees.CONTENT_URI; 171 String[] whereArgs = { 172 Long.toString(eventId) 173 }; 174 mHandler.startQuery(TOKEN_ATTENDEES, null, attUri, 175 EditEventHelper.ATTENDEES_PROJECTION, 176 EditEventHelper.ATTENDEES_WHERE /* selection */, 177 whereArgs /* selection args */, null /* sort order */); 178 } else { 179 setModelIfDone(TOKEN_ATTENDEES); 180 } 181 182 // TOKEN_REMINDERS 183 if (mModel.mHasAlarm) { 184 Uri rUri = Reminders.CONTENT_URI; 185 String[] remArgs = { 186 Long.toString(eventId) 187 }; 188 mHandler.startQuery(TOKEN_REMINDERS, null, rUri, 189 EditEventHelper.REMINDERS_PROJECTION, 190 EditEventHelper.REMINDERS_WHERE /* selection */, 191 remArgs /* selection args */, null /* sort order */); 192 } else { 193 setModelIfDone(TOKEN_REMINDERS); 194 } 195 196 // TOKEN_CALENDARS 197 String[] selArgs = { 198 Long.toString(mModel.mCalendarId) 199 }; 200 mHandler.startQuery(TOKEN_CALENDARS, null, Calendars.CONTENT_URI, 201 EditEventHelper.CALENDARS_PROJECTION, EditEventHelper.CALENDARS_WHERE, 202 selArgs /* selection args */, null /* sort order */); 203 204 setModelIfDone(TOKEN_EVENT); 205 break; 206 case TOKEN_ATTENDEES: 207 try { 208 while (cursor.moveToNext()) { 209 String name = cursor.getString(EditEventHelper.ATTENDEES_INDEX_NAME); 210 String email = cursor.getString(EditEventHelper.ATTENDEES_INDEX_EMAIL); 211 int status = cursor.getInt(EditEventHelper.ATTENDEES_INDEX_STATUS); 212 int relationship = cursor 213 .getInt(EditEventHelper.ATTENDEES_INDEX_RELATIONSHIP); 214 if (relationship == Attendees.RELATIONSHIP_ORGANIZER) { 215 if (email != null) { 216 mModel.mOrganizer = email; 217 mModel.mIsOrganizer = mModel.mOwnerAccount 218 .equalsIgnoreCase(email); 219 mOriginalModel.mOrganizer = email; 220 mOriginalModel.mIsOrganizer = mOriginalModel.mOwnerAccount 221 .equalsIgnoreCase(email); 222 } 223 224 if (TextUtils.isEmpty(name)) { 225 mModel.mOrganizerDisplayName = mModel.mOrganizer; 226 mOriginalModel.mOrganizerDisplayName = 227 mOriginalModel.mOrganizer; 228 } else { 229 mModel.mOrganizerDisplayName = name; 230 mOriginalModel.mOrganizerDisplayName = name; 231 } 232 } 233 234 if (email != null) { 235 if (mModel.mOwnerAccount != null && 236 mModel.mOwnerAccount.equalsIgnoreCase(email)) { 237 int attendeeId = 238 cursor.getInt(EditEventHelper.ATTENDEES_INDEX_ID); 239 mModel.mOwnerAttendeeId = attendeeId; 240 mModel.mSelfAttendeeStatus = status; 241 mOriginalModel.mOwnerAttendeeId = attendeeId; 242 mOriginalModel.mSelfAttendeeStatus = status; 243 continue; 244 } 245 } 246 Attendee attendee = new Attendee(name, email); 247 attendee.mStatus = status; 248 mModel.addAttendee(attendee); 249 mOriginalModel.addAttendee(attendee); 250 } 251 } finally { 252 cursor.close(); 253 } 254 255 setModelIfDone(TOKEN_ATTENDEES); 256 break; 257 case TOKEN_REMINDERS: 258 try { 259 // Add all reminders to the models 260 while (cursor.moveToNext()) { 261 int minutes = cursor.getInt(EditEventHelper.REMINDERS_INDEX_MINUTES); 262 int method = cursor.getInt(EditEventHelper.REMINDERS_INDEX_METHOD); 263 ReminderEntry re = ReminderEntry.valueOf(minutes, method); 264 mModel.mReminders.add(re); 265 mOriginalModel.mReminders.add(re); 266 } 267 268 // Sort appropriately for display 269 Collections.sort(mModel.mReminders); 270 Collections.sort(mOriginalModel.mReminders); 271 } finally { 272 cursor.close(); 273 } 274 275 setModelIfDone(TOKEN_REMINDERS); 276 break; 277 case TOKEN_CALENDARS: 278 try { 279 if (mModel.mCalendarId == -1) { 280 // Populate Calendar spinner only if no calendar is set e.g. new event 281 MatrixCursor matrixCursor = Utils.matrixCursorFromCursor(cursor); 282 if (DEBUG) { 283 Log.d(TAG, "onQueryComplete: setting cursor with " 284 + matrixCursor.getCount() + " calendars"); 285 } 286 mView.setCalendarsCursor(matrixCursor, isAdded() && isResumed()); 287 } else { 288 // Populate model for an existing event 289 EditEventHelper.setModelFromCalendarCursor(mModel, cursor); 290 EditEventHelper.setModelFromCalendarCursor(mOriginalModel, cursor); 291 } 292 } finally { 293 cursor.close(); 294 } 295 296 setModelIfDone(TOKEN_CALENDARS); 297 break; 298 default: 299 cursor.close(); 300 break; 301 } 302 } 303 } 304 305 private void setModelIfDone(int queryType) { 306 synchronized (this) { 307 mOutstandingQueries &= ~queryType; 308 if (mOutstandingQueries == 0) { 309 if (mRestoreModel != null) { 310 mModel = mRestoreModel; 311 } 312 if (mShowModifyDialogOnLaunch && mModification == Utils.MODIFY_UNINITIALIZED) { 313 if (!TextUtils.isEmpty(mModel.mRrule)) { 314 displayEditWhichDialog(); 315 } else { 316 mModification = Utils.MODIFY_ALL; 317 } 318 319 } 320 mView.setModel(mModel); 321 mView.setModification(mModification); 322 if (mMenu != null) { 323 updateActionBar(); 324 } 325 } 326 } 327 } 328 329 private void updateActionBar() { 330 if (mMenu == null) { 331 return; 332 } 333 MenuItem cancelItem = mMenu.findItem(R.id.action_cancel); 334 MenuItem editItem = mMenu.findItem(R.id.action_edit); 335 boolean canModifyEvent = EditEventHelper.canModifyEvent(mModel); 336 boolean canModifyCalendar = EditEventHelper.canModifyCalendar(mModel); 337 338 if (mIsReadOnly) { 339 mMenu.findItem(R.id.action_done).setVisible(false); 340 } 341 if (mModification == Utils.MODIFY_UNINITIALIZED) { 342 cancelItem.setVisible(false); 343 if (canModifyEvent) { 344 editItem.setVisible(true); 345 } else { 346 editItem.setVisible(false); 347 } 348 return; 349 } else { 350 cancelItem.setVisible(true); 351 editItem.setVisible(false); 352 } 353 boolean canRespond = EditEventHelper.canRespond(mModel); 354 355 if (canRespond || canModifyEvent) { 356 cancelItem.setVisible(true); 357 } else { 358 cancelItem.setVisible(false); 359 } 360 } 361 362 public EditEventFragment() { 363 this(null, false, null); 364 } 365 366 public EditEventFragment(EventInfo event, boolean readOnly, Intent intent) { 367 mEvent = event; 368 mIsReadOnly = readOnly; 369 mIntent = intent; 370 setHasOptionsMenu(true); 371 } 372 373 private void startQuery() { 374 mUri = null; 375 mBegin = -1; 376 mEnd = -1; 377 if (mEvent != null) { 378 if (mEvent.id != -1) { 379 mModel.mId = mEvent.id; 380 mUri = ContentUris.withAppendedId(Events.CONTENT_URI, mEvent.id); 381 } 382 if (mEvent.startTime != null) { 383 mBegin = mEvent.startTime.toMillis(true); 384 } 385 if (mEvent.endTime != null) { 386 mEnd = mEvent.endTime.toMillis(true); 387 } 388 } else if (mEventBundle != null) { 389 if (mEventBundle.id != -1) { 390 mModel.mId = mEventBundle.id; 391 mUri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventBundle.id); 392 } 393 mBegin = mEventBundle.start; 394 mEnd = mEventBundle.end; 395 } 396 397 if (mBegin <= 0) { 398 // use a default value instead 399 mBegin = mHelper.constructDefaultStartTime(System.currentTimeMillis()); 400 } 401 if (mEnd < mBegin) { 402 // use a default value instead 403 mEnd = mHelper.constructDefaultEndTime(mBegin); 404 } 405 406 // Kick off the query for the event 407 boolean newEvent = mUri == null; 408 if (!newEvent) { 409 mModel.mCalendarAccessLevel = Calendars.CAL_ACCESS_NONE; 410 mOutstandingQueries = TOKEN_ALL; 411 if (DEBUG) { 412 Log.d(TAG, "startQuery: uri for event is " + mUri.toString()); 413 } 414 mHandler.startQuery(TOKEN_EVENT, null, mUri, EditEventHelper.EVENT_PROJECTION, 415 null /* selection */, null /* selection args */, null /* sort order */); 416 } else { 417 mOutstandingQueries = TOKEN_CALENDARS; 418 if (DEBUG) { 419 Log.d(TAG, "startQuery: Editing a new event."); 420 } 421 mModel.mStart = mBegin; 422 mModel.mEnd = mEnd; 423 mModel.mSelfAttendeeStatus = Attendees.ATTENDEE_STATUS_ACCEPTED; 424 425 // Start a query in the background to read the list of calendars 426 mHandler.startQuery(TOKEN_CALENDARS, null, Calendars.CONTENT_URI, 427 EditEventHelper.CALENDARS_PROJECTION, 428 EditEventHelper.CALENDARS_WHERE_WRITEABLE_VISIBLE, null /* selection args */, 429 null /* sort order */); 430 431 mModification = Utils.MODIFY_ALL; 432 updateActionBar(); 433 mView.setModification(mModification); 434 } 435 } 436 437 @Override 438 public void onAttach(Activity activity) { 439 super.onAttach(activity); 440 mContext = activity; 441 442 mHelper = new EditEventHelper(activity, null); 443 mHandler = new QueryHandler(activity.getContentResolver()); 444 mModel = new CalendarEventModel(activity, mIntent); 445 mInputMethodManager = (InputMethodManager) 446 activity.getSystemService(Context.INPUT_METHOD_SERVICE); 447 } 448 449 @Override 450 public View onCreateView(LayoutInflater inflater, ViewGroup container, 451 Bundle savedInstanceState) { 452// mContext.requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); 453 View view; 454 if (mIsReadOnly) { 455 view = inflater.inflate(R.layout.edit_event_single_column, null); 456 } else { 457 view = inflater.inflate(R.layout.edit_event, null); 458 } 459 mView = new EditEventView(mContext, view, mOnDone); 460 startQuery(); 461 return view; 462 } 463 464 @Override 465 public void onCreate(Bundle savedInstanceState) { 466 super.onCreate(savedInstanceState); 467 if (savedInstanceState != null) { 468 if (savedInstanceState.containsKey(BUNDLE_KEY_MODEL)) { 469 mRestoreModel = (CalendarEventModel) savedInstanceState.getSerializable( 470 BUNDLE_KEY_MODEL); 471 } 472 if (savedInstanceState.containsKey(BUNDLE_KEY_EDIT_STATE)) { 473 mModification = savedInstanceState.getInt(BUNDLE_KEY_EDIT_STATE); 474 } 475 if (savedInstanceState.containsKey(BUNDLE_KEY_EVENT)) { 476 mEventBundle = (EventBundle) savedInstanceState.getSerializable(BUNDLE_KEY_EVENT); 477 } 478 if (savedInstanceState.containsKey(BUNDLE_KEY_READ_ONLY)) { 479 mIsReadOnly = savedInstanceState.getBoolean(BUNDLE_KEY_READ_ONLY); 480 } 481 } 482 } 483 484 485 @Override 486 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 487 super.onCreateOptionsMenu(menu, inflater); 488 inflater.inflate(R.menu.edit_event_title_bar, menu); 489 synchronized (this) { 490 mMenu = menu; 491 updateActionBar(); 492 } 493 } 494 495 @Override 496 public boolean onOptionsItemSelected(MenuItem item) { 497 switch (item.getItemId()) { 498 case R.id.action_done: 499 if (EditEventHelper.canModifyEvent(mModel) || EditEventHelper.canRespond(mModel)) { 500 if (mView != null && mView.prepareForSave()) { 501 if (mModification == Utils.MODIFY_UNINITIALIZED) { 502 mModification = Utils.MODIFY_ALL; 503 } 504 mOnDone.setDoneCode(Utils.DONE_SAVE | Utils.DONE_EXIT); 505 mOnDone.run(); 506 } else { 507 mOnDone.setDoneCode(Utils.DONE_REVERT); 508 mOnDone.run(); 509 } 510 } else if (EditEventHelper.canAddReminders(mModel) && mModel.mId != -1 511 && mOriginalModel != null && mView.prepareForSave()) { 512 saveReminders(); 513 mOnDone.setDoneCode(Utils.DONE_EXIT); 514 mOnDone.run(); 515 } else { 516 mOnDone.setDoneCode(Utils.DONE_REVERT); 517 mOnDone.run(); 518 } 519 break; 520 case R.id.action_cancel: 521 mOnDone.setDoneCode(Utils.DONE_REVERT); 522 mOnDone.run(); 523 break; 524 case R.id.action_edit: 525 if (mIsReadOnly) { 526 CalendarController.getInstance(mContext).sendEventRelatedEvent(this, 527 EventType.EDIT_EVENT, mModel.mId, mModel.mStart, mModel.mEnd, -1, -1, -1); 528 } else if (!TextUtils.isEmpty(mModel.mRrule)) { 529 displayEditWhichDialog(); 530 } else { 531 mModification = Utils.MODIFY_ALL; 532 updateActionBar(); 533 mView.setModification(mModification); 534 } 535 break; 536 } 537 return true; 538 } 539 540 private void saveReminders() { 541 ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(3); 542 boolean changed = EditEventHelper.saveReminders(ops, mModel.mId, mModel.mReminders, 543 mOriginalModel.mReminders, false /* no force save */); 544 545 if (!changed) { 546 return; 547 } 548 549 AsyncQueryService service = new AsyncQueryService(getActivity()); 550 service.startBatch(0, null, Calendars.CONTENT_URI.getAuthority(), ops, 0); 551 // Update the "hasAlarm" field for the event 552 Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mModel.mId); 553 int len = mModel.mReminders.size(); 554 boolean hasAlarm = len > 0; 555 if (hasAlarm != mOriginalModel.mHasAlarm) { 556 ContentValues values = new ContentValues(); 557 values.put(Events.HAS_ALARM, hasAlarm ? 1 : 0); 558 service.startUpdate(0, null, uri, values, null, null, 0); 559 } 560 561 Toast.makeText(mContext, R.string.saving_event, Toast.LENGTH_SHORT).show(); 562 } 563 564 protected void displayEditWhichDialog() { 565 if (!TextUtils.isEmpty(mModel.mRrule) && mModification == Utils.MODIFY_UNINITIALIZED) { 566 final boolean notSynced = TextUtils.isEmpty(mModel.mSyncId); 567 boolean isFirstEventInSeries = mModel.mIsFirstEventInSeries; 568 int itemIndex = 0; 569 CharSequence[] items; 570 571 if (notSynced) { 572 // If this event has not been synced, then don't allow deleting 573 // or changing a single instance. 574 if (isFirstEventInSeries) { 575 // Still display the option so the user knows all events are 576 // changing 577 items = new CharSequence[1]; 578 } else { 579 items = new CharSequence[2]; 580 } 581 } else { 582 if (isFirstEventInSeries) { 583 items = new CharSequence[2]; 584 } else { 585 items = new CharSequence[3]; 586 } 587 items[itemIndex++] = mContext.getText(R.string.modify_event); 588 } 589 items[itemIndex++] = mContext.getText(R.string.modify_all); 590 591 // Do one more check to make sure this remains at the end of the list 592 if (!isFirstEventInSeries) { 593 items[itemIndex++] = mContext.getText(R.string.modify_all_following); 594 } 595 596 // Display the modification dialog. 597 if (mModifyDialog != null) { 598 mModifyDialog.dismiss(); 599 mModifyDialog = null; 600 } 601 mModifyDialog = new AlertDialog.Builder(mContext).setTitle(R.string.edit_event_label) 602 .setItems(items, new OnClickListener() { 603 public void onClick(DialogInterface dialog, int which) { 604 if (which == 0) { 605 // Update this if we start allowing exceptions 606 // to unsynced events in the app 607 mModification = notSynced ? Utils.MODIFY_ALL 608 : Utils.MODIFY_SELECTED; 609 if (mModification == Utils.MODIFY_SELECTED) { 610 mModel.mOriginalSyncId = notSynced ? null : mModel.mSyncId; 611 mModel.mOriginalId = mModel.mId; 612 } 613 } else if (which == 1) { 614 mModification = notSynced ? Utils.MODIFY_ALL_FOLLOWING 615 : Utils.MODIFY_ALL; 616 } else if (which == 2) { 617 mModification = Utils.MODIFY_ALL_FOLLOWING; 618 } 619 620 mView.setModification(mModification); 621 updateActionBar(); 622 } 623 }).show(); 624 } 625 } 626 627 class Done implements EditEventHelper.EditDoneRunnable { 628 private int mCode = -1; 629 630 public void setDoneCode(int code) { 631 mCode = code; 632 } 633 634 public void run() { 635 // We only want this to get called once, either because the user 636 // pressed back/home or one of the buttons on screen 637 mSaveOnDetach = false; 638 if (mModification == Utils.MODIFY_UNINITIALIZED) { 639 // If this is uninitialized the user hit back, the only 640 // changeable item is response to default to all events. 641 mModification = Utils.MODIFY_ALL; 642 } 643 644 if ((mCode & Utils.DONE_SAVE) != 0 && mModel != null 645 && (EditEventHelper.canRespond(mModel) 646 || EditEventHelper.canModifyEvent(mModel)) 647 && mView.prepareForSave() 648 && !isEmptyNewEvent() 649 && mModel.normalizeReminders() 650 && mHelper.saveEvent(mModel, mOriginalModel, mModification)) { 651 int stringResource; 652 if (!mModel.mAttendeesList.isEmpty()) { 653 if (mModel.mUri != null) { 654 stringResource = R.string.saving_event_with_guest; 655 } else { 656 stringResource = R.string.creating_event_with_guest; 657 } 658 } else { 659 if (mModel.mUri != null) { 660 stringResource = R.string.saving_event; 661 } else { 662 stringResource = R.string.creating_event; 663 } 664 } 665 Toast.makeText(mContext, stringResource, Toast.LENGTH_SHORT).show(); 666 } else if ((mCode & Utils.DONE_SAVE) != 0 && mModel != null && isEmptyNewEvent()) { 667 Toast.makeText(mContext, R.string.empty_event, Toast.LENGTH_SHORT).show(); 668 } 669 670 if ((mCode & Utils.DONE_DELETE) != 0 && mOriginalModel != null 671 && EditEventHelper.canModifyCalendar(mOriginalModel)) { 672 long begin = mModel.mStart; 673 long end = mModel.mEnd; 674 int which = -1; 675 switch (mModification) { 676 case Utils.MODIFY_SELECTED: 677 which = DeleteEventHelper.DELETE_SELECTED; 678 break; 679 case Utils.MODIFY_ALL_FOLLOWING: 680 which = DeleteEventHelper.DELETE_ALL_FOLLOWING; 681 break; 682 case Utils.MODIFY_ALL: 683 which = DeleteEventHelper.DELETE_ALL; 684 break; 685 } 686 DeleteEventHelper deleteHelper = new DeleteEventHelper( 687 mContext, mContext, !mIsReadOnly /* exitWhenDone */); 688 deleteHelper.delete(begin, end, mOriginalModel, which); 689 } 690 691 if ((mCode & Utils.DONE_EXIT) != 0) { 692 // This will exit the edit event screen, should be called 693 // when we want to return to the main calendar views 694 EditEventFragment.this.getActivity().finish(); 695 } 696 697 // Hide a software keyboard so that user won't see it even after this Fragment's 698 // disappearing. 699 final View focusedView = mContext.getCurrentFocus(); 700 if (focusedView != null) { 701 mInputMethodManager.hideSoftInputFromWindow(focusedView.getWindowToken(), 0); 702 focusedView.clearFocus(); 703 } 704 } 705 } 706 707 boolean isEmptyNewEvent() { 708 if (mOriginalModel != null) { 709 // Not new 710 return false; 711 } 712 713 return isEmpty(); 714 } 715 716 private boolean isEmpty() { 717 if (mModel.mTitle != null) { 718 String title = mModel.mTitle.trim(); 719 if (title.length() > 0) { 720 return false; 721 } 722 } 723 724 if (mModel.mLocation != null) { 725 String location = mModel.mLocation.trim(); 726 if (location.length() > 0) { 727 return false; 728 } 729 } 730 731 if (mModel.mDescription != null) { 732 String description = mModel.mDescription.trim(); 733 if (description.length() > 0) { 734 return false; 735 } 736 } 737 738 return true; 739 } 740 741 @Override 742 public void onPause() { 743 Activity act = getActivity(); 744 if (mSaveOnDetach && act != null && !mIsReadOnly && !act.isChangingConfigurations() 745 && mView.prepareForSave()) { 746 mOnDone.setDoneCode(Utils.DONE_SAVE); 747 mOnDone.run(); 748 } 749 super.onPause(); 750 } 751 752 @Override 753 public void onDestroy() { 754 if (mView != null) { 755 mView.setModel(null); 756 } 757 if (mModifyDialog != null) { 758 mModifyDialog.dismiss(); 759 mModifyDialog = null; 760 } 761 super.onDestroy(); 762 } 763 764 @Override 765 public void eventsChanged() { 766 // TODO Requery to see if event has changed 767 } 768 769 @Override 770 public void onSaveInstanceState(Bundle outState) { 771 mView.prepareForSave(); 772 outState.putSerializable(BUNDLE_KEY_MODEL, mModel); 773 outState.putInt(BUNDLE_KEY_EDIT_STATE, mModification); 774 if (mEventBundle == null && mEvent != null) { 775 mEventBundle = new EventBundle(); 776 mEventBundle.id = mEvent.id; 777 if (mEvent.startTime != null) { 778 mEventBundle.start = mEvent.startTime.toMillis(true); 779 } 780 if (mEvent.endTime != null) { 781 mEventBundle.end = mEvent.startTime.toMillis(true); 782 } 783 } 784 785 outState.putSerializable(BUNDLE_KEY_EVENT, mEventBundle); 786 outState.putBoolean(BUNDLE_KEY_READ_ONLY, mIsReadOnly); 787 } 788 789 @Override 790 public long getSupportedEventTypes() { 791 return EventType.USER_HOME; 792 } 793 794 @Override 795 public void handleEvent(EventInfo event) { 796 // It's currently unclear if we want to save the event or not when home 797 // is pressed. When creating a new event we shouldn't save since we 798 // can't get the id of the new event easily. 799 if ((false && event.eventType == EventType.USER_HOME) || (event.eventType == EventType.GO_TO 800 && mSaveOnDetach)) { 801 if (mView != null && mView.prepareForSave()) { 802 mOnDone.setDoneCode(Utils.DONE_SAVE); 803 mOnDone.run(); 804 } 805 } 806 } 807 808 private static class EventBundle implements Serializable { 809 long id = -1; 810 long start = -1; 811 long end = -1; 812 } 813} 814