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