FileDocCategorySizeDatePackage
EditEvent.javaAPI DocAndroid 1.5 API69892Wed May 06 22:42:42 BST 2009com.android.calendar

EditEvent

public class EditEvent extends android.app.Activity implements android.content.DialogInterface.OnClickListener, View.OnClickListener, android.content.DialogInterface.OnCancelListener

Fields Summary
public static final String
EVENT_ALL_DAY
This is the symbolic name for the key used to pass in the boolean for creating all-day events that is part of the extra data of the intent. This is used only for creating new events and is set to true if the default for the new event should be an all-day event.
private static final int
MAX_REMINDERS
private static final int
MENU_GROUP_REMINDER
private static final int
MENU_GROUP_SHOW_OPTIONS
private static final int
MENU_GROUP_HIDE_OPTIONS
private static final int
MENU_ADD_REMINDER
private static final int
MENU_SHOW_EXTRA_OPTIONS
private static final int
MENU_HIDE_EXTRA_OPTIONS
private static final String[]
EVENT_PROJECTION
private static final int
EVENT_INDEX_ID
private static final int
EVENT_INDEX_TITLE
private static final int
EVENT_INDEX_DESCRIPTION
private static final int
EVENT_INDEX_EVENT_LOCATION
private static final int
EVENT_INDEX_ALL_DAY
private static final int
EVENT_INDEX_HAS_ALARM
private static final int
EVENT_INDEX_CALENDAR_ID
private static final int
EVENT_INDEX_DTSTART
private static final int
EVENT_INDEX_DURATION
private static final int
EVENT_INDEX_TIMEZONE
private static final int
EVENT_INDEX_RRULE
private static final int
EVENT_INDEX_SYNC_ID
private static final int
EVENT_INDEX_TRANSPARENCY
private static final int
EVENT_INDEX_VISIBILITY
private static final String[]
CALENDARS_PROJECTION
private static final int
CALENDARS_INDEX_DISPLAY_NAME
private static final int
CALENDARS_INDEX_TIMEZONE
private static final String
CALENDARS_WHERE
private static final String[]
REMINDERS_PROJECTION
private static final int
REMINDERS_INDEX_MINUTES
private static final String
REMINDERS_WHERE
private static final int
DOES_NOT_REPEAT
private static final int
REPEATS_DAILY
private static final int
REPEATS_EVERY_WEEKDAY
private static final int
REPEATS_WEEKLY_ON_DAY
private static final int
REPEATS_MONTHLY_ON_DAY_COUNT
private static final int
REPEATS_MONTHLY_ON_DAY
private static final int
REPEATS_YEARLY
private static final int
REPEATS_CUSTOM
private static final int
MODIFY_UNINITIALIZED
private static final int
MODIFY_SELECTED
private static final int
MODIFY_ALL
private static final int
MODIFY_ALL_FOLLOWING
private static final int
DAY_IN_SECONDS
private int
mFirstDayOfWeek
private android.net.Uri
mUri
private android.database.Cursor
mEventCursor
private android.database.Cursor
mCalendarsCursor
private android.widget.Button
mStartDateButton
private android.widget.Button
mEndDateButton
private android.widget.Button
mStartTimeButton
private android.widget.Button
mEndTimeButton
private android.widget.Button
mSaveButton
private android.widget.Button
mDeleteButton
private android.widget.Button
mDiscardButton
private android.widget.CheckBox
mAllDayCheckBox
private android.widget.Spinner
mCalendarsSpinner
private android.widget.Spinner
mRepeatsSpinner
private android.widget.Spinner
mAvailabilitySpinner
private android.widget.Spinner
mVisibilitySpinner
private android.widget.TextView
mTitleTextView
private android.widget.TextView
mLocationTextView
private android.widget.TextView
mDescriptionTextView
private android.view.View
mRemindersSeparator
private android.widget.LinearLayout
mRemindersContainer
private android.widget.LinearLayout
mExtraOptions
private ArrayList
mOriginalMinutes
private ArrayList
mReminderItems
private android.pim.EventRecurrence
mEventRecurrence
private String
mRrule
private boolean
mCalendarsQueryComplete
private boolean
mSaveAfterQueryComplete
private android.app.ProgressDialog
mLoadingCalendarsDialog
private android.app.AlertDialog
mNoCalendarsDialog
private android.content.ContentValues
mInitialValues
private String
mSyncId
If the repeating event is created on the phone and it hasn't been synced yet to the web server, then there is a bug where you can't delete or change an instance of the repeating event. This case can be detected with mSyncId. If mSyncId == null, then the repeating event has not been synced to the phone, in which case we won't allow the user to change one instance.
private ArrayList
mRecurrenceIndexes
private ArrayList
mReminderValues
private ArrayList
mReminderLabels
private android.text.format.Time
mStartTime
private android.text.format.Time
mEndTime
private int
mModification
private int
mDefaultReminderMinutes
private DeleteEventHelper
mDeleteEventHelper
private QueryHandler
mQueryHandler
Constructors Summary
Methods Summary
static voidaddMinutesToList(android.content.Context context, java.util.ArrayList values, java.util.ArrayList labels, int minutes)

        int index = values.indexOf(minutes);
        if (index != -1) {
            return;
        }
        
        // The requested "minutes" does not exist in the list, so insert it
        // into the list.
        
        String label = constructReminderLabel(context, minutes, false);
        int len = values.size();
        for (int i = 0; i < len; i++) {
            if (minutes < values.get(i)) {
                values.add(i, minutes);
                labels.add(i, label);
                return;
            }
        }
        
        values.add(minutes);
        labels.add(len, label);
    
private voidaddRecurrenceRule(android.content.ContentValues values)

        updateRecurrenceRule();

        if (mRrule == null) {
            return;
        }
        
        values.put(Events.RRULE, mRrule);
        long end = mEndTime.toMillis(true /* ignore dst */);
        long start = mStartTime.toMillis(true /* ignore dst */);
        String duration;

        boolean isAllDay = mAllDayCheckBox.isChecked();
        if (isAllDay) {
            long days = (end - start + DateUtils.DAY_IN_MILLIS - 1) / DateUtils.DAY_IN_MILLIS;
            duration = "P" + days + "D";
        } else {
            long seconds = (end - start) / DateUtils.SECOND_IN_MILLIS;
            duration = "P" + seconds + "S";
        }
        values.put(Events.DURATION, duration);
    
static booleanaddReminder(android.app.Activity activity, View.OnClickListener listener, java.util.ArrayList items, java.util.ArrayList values, java.util.ArrayList labels, int minutes)


        if (items.size() >= MAX_REMINDERS) {
            return false;
        }

        LayoutInflater inflater = activity.getLayoutInflater();
        LinearLayout parent = (LinearLayout) activity.findViewById(R.id.reminder_items_container);
        LinearLayout reminderItem = (LinearLayout) inflater.inflate(R.layout.edit_reminder_item, null);
        parent.addView(reminderItem);
        
        Spinner spinner = (Spinner) reminderItem.findViewById(R.id.reminder_value);
        Resources res = activity.getResources();
        spinner.setPrompt(res.getString(R.string.reminders_label));
        int resource = android.R.layout.simple_spinner_item;
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(activity, resource, labels);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);
        
        ImageButton reminderRemoveButton;
        reminderRemoveButton = (ImageButton) reminderItem.findViewById(R.id.reminder_remove);
        reminderRemoveButton.setOnClickListener(listener);

        int index = findMinutesInReminderList(values, minutes);
        spinner.setSelection(index);
        items.add(reminderItem);

        return true;
    
private voidaddReminder()

        // TODO: when adding a new reminder, make it different from the
        // last one in the list (if any).
        if (mDefaultReminderMinutes == 0) {
            addReminder(this, this, mReminderItems, mReminderValues,
                    mReminderLabels, 10 /* minutes */);
        } else {
            addReminder(this, this, mReminderItems, mReminderValues,
                    mReminderLabels, mDefaultReminderMinutes);
        }
        updateRemindersVisibility();
    
private voidcheckTimeDependentFields(android.content.ContentValues values)

        long oldBegin = mInitialValues.getAsLong(EVENT_BEGIN_TIME);
        long oldEnd = mInitialValues.getAsLong(EVENT_END_TIME);
        boolean oldAllDay = mInitialValues.getAsInteger(Events.ALL_DAY) != 0;
        String oldRrule = mInitialValues.getAsString(Events.RRULE);
        String oldTimezone = mInitialValues.getAsString(Events.EVENT_TIMEZONE);
        
        long newBegin = values.getAsLong(Events.DTSTART);
        long newEnd = values.getAsLong(Events.DTEND);
        boolean newAllDay = values.getAsInteger(Events.ALL_DAY) != 0;
        String newRrule = values.getAsString(Events.RRULE);
        String newTimezone = values.getAsString(Events.EVENT_TIMEZONE);
        
        // If none of the time-dependent fields changed, then remove them.
        if (oldBegin == newBegin && oldEnd == newEnd && oldAllDay == newAllDay
                && TextUtils.equals(oldRrule, newRrule)
                && TextUtils.equals(oldTimezone, newTimezone)) {
            values.remove(Events.DTSTART);
            values.remove(Events.DTEND);
            values.remove(Events.DURATION);
            values.remove(Events.ALL_DAY);
            values.remove(Events.RRULE);
            values.remove(Events.EVENT_TIMEZONE);
            return;
        }

        if (oldRrule == null || newRrule == null) {
            return;
        }

        // If we are modifying all events then we need to set DTSTART to the
        // start time of the first event in the series, not the current
        // date and time.  If the start time of the event was changed
        // (from, say, 3pm to 4pm), then we want to add the time difference
        // to the start time of the first event in the series (the DTSTART
        // value).  If we are modifying one instance or all following instances,
        // then we leave the DTSTART field alone.
        if (mModification == MODIFY_ALL) {
            long oldStartMillis = mEventCursor.getLong(EVENT_INDEX_DTSTART);
            if (oldBegin != newBegin) {
                // The user changed the start time of this event
                long offset = newBegin - oldBegin;
                oldStartMillis += offset;
            }
            values.put(Events.DTSTART, oldStartMillis);
        }
    
static java.lang.StringconstructReminderLabel(android.content.Context context, int minutes, boolean abbrev)

        Resources resources = context.getResources();
        int value, resId;
        
        if (minutes % 60 != 0) {
            value = minutes;
            if (abbrev) {
                resId = R.plurals.Nmins;
            } else {
                resId = R.plurals.Nminutes;
            }
        } else if (minutes % (24 * 60) != 0) {
            value = minutes / 60;
            resId = R.plurals.Nhours;
        } else {
            value = minutes / ( 24 * 60);
            resId = R.plurals.Ndays;
        }

        String format = resources.getQuantityString(resId, value);
        return String.format(format, value);
    
private static intfindMinutesInReminderList(java.util.ArrayList values, int minutes)
Finds the index of the given "minutes" in the "values" list.

param
values the list of minutes corresponding to the spinner choices
param
minutes the minutes to search for in the values list
return
the index of "minutes" in the "values" list

        int index = values.indexOf(minutes);
        if (index == -1) {
            // This should never happen.
            Log.e("Cal", "Cannot find minutes (" + minutes + ") in list");
            return 0;
        }
        return index;
    
private android.content.ContentValuesgetContentValuesFromUi()

        String title = mTitleTextView.getText().toString();
        boolean isAllDay = mAllDayCheckBox.isChecked();
        String location = mLocationTextView.getText().toString();
        String description = mDescriptionTextView.getText().toString();

        ContentValues values = new ContentValues();

        String timezone = null;
        long startMillis;
        long endMillis;
        long calendarId;
        if (isAllDay) {
            // Reset start and end time, increment the monthDay by 1, and set
            // the timezone to UTC, as required for all-day events.
            timezone = Time.TIMEZONE_UTC;
            mStartTime.hour = 0;
            mStartTime.minute = 0;
            mStartTime.second = 0;
            mStartTime.timezone = timezone;
            startMillis = mStartTime.normalize(true);

            mEndTime.hour = 0;
            mEndTime.minute = 0;
            mEndTime.second = 0;
            mEndTime.monthDay++;
            mEndTime.timezone = timezone;
            endMillis = mEndTime.normalize(true);
            
            if (mEventCursor == null) {
                // This is a new event
                calendarId = mCalendarsSpinner.getSelectedItemId();
            } else {
                calendarId = mInitialValues.getAsLong(Events.CALENDAR_ID);
            }
        } else {
            startMillis = mStartTime.toMillis(true);
            endMillis = mEndTime.toMillis(true);
            if (mEventCursor != null) {
                // This is an existing event
                timezone = mEventCursor.getString(EVENT_INDEX_TIMEZONE);
                
                // The timezone might be null if we are changing an existing
                // all-day event to a non-all-day event.  We need to assign
                // a timezone to the non-all-day event.
                if (TextUtils.isEmpty(timezone)) {
                    timezone = TimeZone.getDefault().getID();
                }
                calendarId = mInitialValues.getAsLong(Events.CALENDAR_ID);
            } else {
                // This is a new event
                calendarId = mCalendarsSpinner.getSelectedItemId();
                
                // The timezone for a new event is the currently displayed
                // timezone, NOT the timezone of the containing calendar.
                timezone = TimeZone.getDefault().getID();
            }
        }

        values.put(Events.CALENDAR_ID, calendarId);
        values.put(Events.EVENT_TIMEZONE, timezone);
        values.put(Events.TITLE, title);
        values.put(Events.ALL_DAY, isAllDay ? 1 : 0);
        values.put(Events.DTSTART, startMillis);
        values.put(Events.DTEND, endMillis);
        values.put(Events.DESCRIPTION, description);
        values.put(Events.EVENT_LOCATION, location);
        values.put(Events.TRANSPARENCY, mAvailabilitySpinner.getSelectedItemPosition());

        int visibility = mVisibilitySpinner.getSelectedItemPosition();
        if (visibility > 0) {
            // For now we the array contains the values 0, 2, and 3. We add one to match.
            visibility++;
        }
        values.put(Events.VISIBILITY, visibility);

        return values;
    
private voidinitFromIntent(android.content.Intent intent)

        String title = intent.getStringExtra(Events.TITLE);
        if (title != null) {
            mTitleTextView.setText(title);
        }
        
        String location = intent.getStringExtra(Events.EVENT_LOCATION);
        if (location != null) {
            mLocationTextView.setText(location);
        }
        
        String description = intent.getStringExtra(Events.DESCRIPTION);
        if (description != null) {
            mDescriptionTextView.setText(description);
        }
        
        int availability = intent.getIntExtra(Events.TRANSPARENCY, -1);
        if (availability != -1) {
            mAvailabilitySpinner.setSelection(availability);
        }
        
        int visibility = intent.getIntExtra(Events.VISIBILITY, -1);
        if (visibility != -1) {
            mVisibilitySpinner.setSelection(visibility);
        }
        
        String rrule = intent.getStringExtra(Events.RRULE);
        if (rrule != null) {
            mRrule = rrule;
            mEventRecurrence.parse(rrule);
        }
    
private booleanisCustomRecurrence()


        if (mEventRecurrence.until != null || mEventRecurrence.interval != 0) {
            return true;
        }

        if (mEventRecurrence.freq == 0) {
            return false;
        }

        switch (mEventRecurrence.freq) {
        case EventRecurrence.DAILY:
            return false;
        case EventRecurrence.WEEKLY:
            if (mEventRecurrence.repeatsOnEveryWeekDay() && isWeekdayEvent()) {
                return false;
            } else if (mEventRecurrence.bydayCount == 1) {
                return false;
            }
            break;
        case EventRecurrence.MONTHLY:
            if (mEventRecurrence.repeatsMonthlyOnDayCount()) {
                return false;
            } else if (mEventRecurrence.bydayCount == 0 && mEventRecurrence.bymonthdayCount == 1) {
                return false;
            }
            break;
        case EventRecurrence.YEARLY:
            return false;
        }

        return true;
    
private booleanisEmpty()

        String title = mTitleTextView.getText().toString();
        if (title.length() > 0) {
            return false;
        }

        String location = mLocationTextView.getText().toString();
        if (location.length() > 0) {
            return false;
        }

        String description = mDescriptionTextView.getText().toString();
        if (description.length() > 0) {
            return false;
        }

        return true;
    
private booleanisFirstEventInSeries()

        int dtStart = mEventCursor.getColumnIndexOrThrow(Events.DTSTART);
        long start = mEventCursor.getLong(dtStart);
        return start == mStartTime.toMillis(true);
    
private booleanisWeekdayEvent()

        if (mStartTime.weekDay != Time.SUNDAY && mStartTime.weekDay != Time.SATURDAY) {
            return true;
        }
        return false;
    
public voidonCancel(android.content.DialogInterface dialog)

        if (dialog == mLoadingCalendarsDialog) {
            mSaveAfterQueryComplete = false;
        } else if (dialog == mNoCalendarsDialog) {
            finish();
        }
    
public voidonClick(android.view.View v)

        if (v == mSaveButton) {
            if (save()) {
                finish();
            }
            return;
        }
        
        if (v == mDeleteButton) {
            long begin = mStartTime.toMillis(false /* use isDst */);
            long end = mEndTime.toMillis(false /* use isDst */);
            int which = -1;
            switch (mModification) {
            case MODIFY_SELECTED:
                which = DeleteEventHelper.DELETE_SELECTED;
                break;
            case MODIFY_ALL_FOLLOWING:
                which = DeleteEventHelper.DELETE_ALL_FOLLOWING;
                break;
            case MODIFY_ALL:
                which = DeleteEventHelper.DELETE_ALL;
                break;
            }
            mDeleteEventHelper.delete(begin, end, mEventCursor, which);
            return;
        }
        
        if (v == mDiscardButton) {
            finish();
            return;
        }
        
        // This must be a click on one of the "remove reminder" buttons
        LinearLayout reminderItem = (LinearLayout) v.getParent();
        LinearLayout parent = (LinearLayout) reminderItem.getParent();
        parent.removeView(reminderItem);
        mReminderItems.remove(reminderItem);
        updateRemindersVisibility();
    
public voidonClick(android.content.DialogInterface dialog, int which)

        if (dialog == mNoCalendarsDialog) {
            finish();
        }
    
protected voidonCreate(android.os.Bundle icicle)

        super.onCreate(icicle);
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        setContentView(R.layout.edit_event);

        mFirstDayOfWeek = Calendar.getInstance().getFirstDayOfWeek();

        mStartTime = new Time();
        mEndTime = new Time();

        Intent intent = getIntent();
        mUri = intent.getData();

        if (mUri != null) {
            mEventCursor = managedQuery(mUri, EVENT_PROJECTION, null, null);
            if (mEventCursor == null || mEventCursor.getCount() == 0) {
                // The cursor is empty. This can happen if the event was deleted.
                finish();
                return;
            }
        }

        long begin = intent.getLongExtra(EVENT_BEGIN_TIME, 0);
        long end = intent.getLongExtra(EVENT_END_TIME, 0);

        boolean allDay = false;
        if (mEventCursor != null) {
            // The event already exists so fetch the all-day status
            mEventCursor.moveToFirst();
            allDay = mEventCursor.getInt(EVENT_INDEX_ALL_DAY) != 0;
            String rrule = mEventCursor.getString(EVENT_INDEX_RRULE);
            String timezone = mEventCursor.getString(EVENT_INDEX_TIMEZONE);
            long calendarId = mEventCursor.getInt(EVENT_INDEX_CALENDAR_ID);
            
            // Remember the initial values
            mInitialValues = new ContentValues();
            mInitialValues.put(EVENT_BEGIN_TIME, begin);
            mInitialValues.put(EVENT_END_TIME, end);
            mInitialValues.put(Events.ALL_DAY, allDay ? 1 : 0);
            mInitialValues.put(Events.RRULE, rrule);
            mInitialValues.put(Events.EVENT_TIMEZONE, timezone);
            mInitialValues.put(Events.CALENDAR_ID, calendarId);
        } else {
            // We are creating a new event, so set the default from the
            // intent (if specified).
            allDay = intent.getBooleanExtra(EVENT_ALL_DAY, false);
            
            // Start the spinner
            getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
                    Window.PROGRESS_VISIBILITY_ON);

            // Start a query in the background to read the list of calendars
            mQueryHandler = new QueryHandler(getContentResolver());
            mQueryHandler.startQuery(0, null, Calendars.CONTENT_URI, CALENDARS_PROJECTION,
                    CALENDARS_WHERE, null /* selection args */, null /* sort order */);
        }

        // If the event is all-day, read the times in UTC timezone
        if (begin != 0) {
            if (allDay) {
                String tz = mStartTime.timezone;
                mStartTime.timezone = Time.TIMEZONE_UTC;
                mStartTime.set(begin);
                mStartTime.timezone = tz;

                // Calling normalize to calculate isDst
                mStartTime.normalize(true);
            } else {
                mStartTime.set(begin);
            }
        }

        if (end != 0) {
            if (allDay) {
                String tz = mStartTime.timezone;
                mEndTime.timezone = Time.TIMEZONE_UTC;
                mEndTime.set(end);
                mEndTime.timezone = tz;

                // Calling normalize to calculate isDst
                mEndTime.normalize(true);
            } else {
                mEndTime.set(end);
            }
        }

        // cache all the widgets
        mTitleTextView = (TextView) findViewById(R.id.title);
        mLocationTextView = (TextView) findViewById(R.id.location);
        mDescriptionTextView = (TextView) findViewById(R.id.description);
        mStartDateButton = (Button) findViewById(R.id.start_date);
        mEndDateButton = (Button) findViewById(R.id.end_date);
        mStartTimeButton = (Button) findViewById(R.id.start_time);
        mEndTimeButton = (Button) findViewById(R.id.end_time);
        mAllDayCheckBox = (CheckBox) findViewById(R.id.is_all_day);
        mCalendarsSpinner = (Spinner) findViewById(R.id.calendars);
        mRepeatsSpinner = (Spinner) findViewById(R.id.repeats);
        mAvailabilitySpinner = (Spinner) findViewById(R.id.availability);
        mVisibilitySpinner = (Spinner) findViewById(R.id.visibility);
        mRemindersSeparator = findViewById(R.id.reminders_separator);
        mRemindersContainer = (LinearLayout) findViewById(R.id.reminder_items_container);
        mExtraOptions = (LinearLayout) findViewById(R.id.extra_options_container);

        mAllDayCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    if (mEndTime.hour == 0 && mEndTime.minute == 0) {
                        mEndTime.monthDay--;
                        long endMillis = mEndTime.normalize(true);

                        // Do not allow an event to have an end time before the start time.
                        if (mEndTime.before(mStartTime)) {
                            mEndTime.set(mStartTime);
                            endMillis = mEndTime.normalize(true);
                        }
                        setDate(mEndDateButton, endMillis);
                        setTime(mEndTimeButton, endMillis);
                    }

                    mStartTimeButton.setVisibility(View.GONE);
                    mEndTimeButton.setVisibility(View.GONE);
                } else {
                    if (mEndTime.hour == 0 && mEndTime.minute == 0) {
                        mEndTime.monthDay++;
                        long endMillis = mEndTime.normalize(true);
                        setDate(mEndDateButton, endMillis);
                        setTime(mEndTimeButton, endMillis);
                    }

                    mStartTimeButton.setVisibility(View.VISIBLE);
                    mEndTimeButton.setVisibility(View.VISIBLE);
                }
            }
        });

        if (allDay) {
            mAllDayCheckBox.setChecked(true);
        } else {
            mAllDayCheckBox.setChecked(false);
        }

        mSaveButton = (Button) findViewById(R.id.save);
        mSaveButton.setOnClickListener(this);

        mDeleteButton = (Button) findViewById(R.id.delete);
        mDeleteButton.setOnClickListener(this);

        mDiscardButton = (Button) findViewById(R.id.discard);
        mDiscardButton.setOnClickListener(this);

        // Initialize the reminder values array.
        Resources r = getResources();
        String[] strings = r.getStringArray(R.array.reminder_minutes_values);
        int size = strings.length;
        ArrayList<Integer> list = new ArrayList<Integer>(size);
        for (int i = 0 ; i < size ; i++) {
            list.add(Integer.parseInt(strings[i]));
        }
        mReminderValues = list;
        String[] labels = r.getStringArray(R.array.reminder_minutes_labels);
        mReminderLabels = new ArrayList<String>(Arrays.asList(labels));

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        String durationString =
                prefs.getString(CalendarPreferenceActivity.KEY_DEFAULT_REMINDER, "0");
        mDefaultReminderMinutes = Integer.parseInt(durationString);

        // Reminders cursor
        boolean hasAlarm = (mEventCursor != null)
                && (mEventCursor.getInt(EVENT_INDEX_HAS_ALARM) != 0);
        if (hasAlarm) {
            Uri uri = Reminders.CONTENT_URI;
            long eventId = mEventCursor.getLong(EVENT_INDEX_ID);
            String where = String.format(REMINDERS_WHERE, eventId);
            ContentResolver cr = getContentResolver();
            Cursor reminderCursor = cr.query(uri, REMINDERS_PROJECTION, where, null, null);
            try {
                // First pass: collect all the custom reminder minutes (e.g.,
                // a reminder of 8 minutes) into a global list.
                while (reminderCursor.moveToNext()) {
                    int minutes = reminderCursor.getInt(REMINDERS_INDEX_MINUTES);
                    EditEvent.addMinutesToList(this, mReminderValues, mReminderLabels, minutes);
                }
                
                // Second pass: create the reminder spinners
                reminderCursor.moveToPosition(-1);
                while (reminderCursor.moveToNext()) {
                    int minutes = reminderCursor.getInt(REMINDERS_INDEX_MINUTES);
                    mOriginalMinutes.add(minutes);
                    EditEvent.addReminder(this, this, mReminderItems, mReminderValues,
                            mReminderLabels, minutes);
                }
            } finally {
                reminderCursor.close();
            }
        }
        updateRemindersVisibility();

        // Setup the + Add Reminder Button
        View.OnClickListener addReminderOnClickListener = new View.OnClickListener() {
            public void onClick(View v) {
                addReminder();
            }
        };        
        ImageButton reminderRemoveButton = (ImageButton) findViewById(R.id.reminder_add);
        reminderRemoveButton.setOnClickListener(addReminderOnClickListener);

        mDeleteEventHelper = new DeleteEventHelper(this, true /* exit when done */);

        if (mEventCursor == null) {
            // Allow the intent to specify the fields in the event.
            // This will allow other apps to create events easily.
            initFromIntent(intent);
        }
    
public booleanonCreateOptionsMenu(android.view.Menu menu)

        MenuItem item;
        item = menu.add(MENU_GROUP_REMINDER, MENU_ADD_REMINDER, 0,
                R.string.add_new_reminder);
        item.setIcon(R.drawable.ic_menu_reminder);
        item.setAlphabeticShortcut('r");

        item = menu.add(MENU_GROUP_SHOW_OPTIONS, MENU_SHOW_EXTRA_OPTIONS, 0,
                R.string.edit_event_show_extra_options);
        item.setIcon(R.drawable.ic_menu_show_list);
        item = menu.add(MENU_GROUP_HIDE_OPTIONS, MENU_HIDE_EXTRA_OPTIONS, 0,
                R.string.edit_event_hide_extra_options);
        item.setIcon(R.drawable.ic_menu_show_list);

        return super.onCreateOptionsMenu(menu);
    
public booleanonKeyDown(int keyCode, android.view.KeyEvent event)

        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK:
                // If we are creating a new event, do not create it if the
                // title, location and description are all empty, in order to
                // prevent accidental "no subject" event creations.
                if (mUri != null || !isEmpty()) {
                    if (!save()) {
                        // We cannot exit this activity because the calendars
                        // are still loading.
                        return true;
                    }
                }
                break;
        }

        return super.onKeyDown(keyCode, event);
    
public booleanonOptionsItemSelected(android.view.MenuItem item)

        switch (item.getItemId()) {
        case MENU_ADD_REMINDER:
            addReminder();
            return true;
        case MENU_SHOW_EXTRA_OPTIONS:
            mExtraOptions.setVisibility(View.VISIBLE);
            return true;
        case MENU_HIDE_EXTRA_OPTIONS:
            mExtraOptions.setVisibility(View.GONE);
            return true;
        }
        return super.onOptionsItemSelected(item);
    
public booleanonPrepareOptionsMenu(android.view.Menu menu)

        if (mReminderItems.size() < MAX_REMINDERS) {
            menu.setGroupVisible(MENU_GROUP_REMINDER, true);
            menu.setGroupEnabled(MENU_GROUP_REMINDER, true);
        } else {
            menu.setGroupVisible(MENU_GROUP_REMINDER, false);
            menu.setGroupEnabled(MENU_GROUP_REMINDER, false);
        }

        if (mExtraOptions.getVisibility() == View.VISIBLE) {
            menu.setGroupVisible(MENU_GROUP_SHOW_OPTIONS, false);
            menu.setGroupVisible(MENU_GROUP_HIDE_OPTIONS, true);
        } else {
            menu.setGroupVisible(MENU_GROUP_SHOW_OPTIONS, true);
            menu.setGroupVisible(MENU_GROUP_HIDE_OPTIONS, false);
        }

        return super.onPrepareOptionsMenu(menu);
    
protected voidonResume()

        super.onResume();

        if (mUri != null) {
            if (mEventCursor == null || mEventCursor.getCount() == 0) {
                // The cursor is empty. This can happen if the event was deleted.
                finish();
                return;
            }
        }
        
        if (mEventCursor != null) {
            Cursor cursor = mEventCursor;
            cursor.moveToFirst();

            mRrule = cursor.getString(EVENT_INDEX_RRULE);
            String title = cursor.getString(EVENT_INDEX_TITLE);
            String description = cursor.getString(EVENT_INDEX_DESCRIPTION);
            String location = cursor.getString(EVENT_INDEX_EVENT_LOCATION);
            int availability = cursor.getInt(EVENT_INDEX_TRANSPARENCY);
            int visibility = cursor.getInt(EVENT_INDEX_VISIBILITY);
            if (visibility > 0) {
                // For now we the array contains the values 0, 2, and 3. We subtract one to match.
                visibility--;
            }

            if (!TextUtils.isEmpty(mRrule) && mModification == MODIFY_UNINITIALIZED) {
                // If this event has not been synced, then don't allow deleting
                // or changing a single instance.
                mSyncId = cursor.getString(EVENT_INDEX_SYNC_ID);
                mEventRecurrence.parse(mRrule);

                // If we haven't synced this repeating event yet, then don't
                // allow the user to change just one instance.
                int itemIndex = 0;
                CharSequence[] items;
                if (mSyncId == null) {
                    items = new CharSequence[2];
                } else {
                    items = new CharSequence[3];
                    items[itemIndex++] = getText(R.string.modify_event);
                }
                items[itemIndex++] = getText(R.string.modify_all);
                items[itemIndex++] = getText(R.string.modify_all_following);

                // Display the modification dialog.
                new AlertDialog.Builder(this)
                        .setOnCancelListener(new OnCancelListener() {
                            public void onCancel(DialogInterface dialog) {
                                finish();
                            }
                        })
                        .setTitle(R.string.edit_event_label)
                        .setItems(items, new OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                if (which == 0) {
                                    mModification =
                                            (mSyncId == null) ? MODIFY_ALL : MODIFY_SELECTED;
                                } else if (which == 1) {
                                    mModification =
                                        (mSyncId == null) ? MODIFY_ALL_FOLLOWING : MODIFY_ALL;
                                } else if (which == 2) {
                                    mModification = MODIFY_ALL_FOLLOWING;
                                }
                                
                                // If we are modifying all the events in a
                                // series then disable and ignore the date.
                                if (mModification == MODIFY_ALL) {
                                    mStartDateButton.setEnabled(false);
                                    mEndDateButton.setEnabled(false);
                                } else if (mModification == MODIFY_SELECTED) {
                                    mRepeatsSpinner.setEnabled(false);
                                }
                            }
                        })
                        .show();
            }

            mTitleTextView.setText(title);
            mLocationTextView.setText(location);
            mDescriptionTextView.setText(description);
            mAvailabilitySpinner.setSelection(availability);
            mVisibilitySpinner.setSelection(visibility);

            // This is an existing event so hide the calendar spinner
            // since we can't change the calendar.
            View calendarGroup = findViewById(R.id.calendar_group);
            calendarGroup.setVisibility(View.GONE);
        } else if (Time.isEpoch(mStartTime) && Time.isEpoch(mEndTime)) {
            mStartTime.setToNow();

            // Round the time to the nearest half hour.
            mStartTime.second = 0;
            int minute = mStartTime.minute;
            if (minute > 0 && minute <= 30) {
                mStartTime.minute = 30;
            } else {
                mStartTime.minute = 0;
                mStartTime.hour += 1;
            }

            long startMillis = mStartTime.normalize(true /* ignore isDst */);
            mEndTime.set(startMillis + DateUtils.HOUR_IN_MILLIS);
        } else {
            // New event - set the default reminder
            if (mDefaultReminderMinutes != 0) {
                addReminder(this, this, mReminderItems, mReminderValues,
                        mReminderLabels, mDefaultReminderMinutes);
            }

            // Hide delete button
            mDeleteButton.setVisibility(View.GONE);
        }

        updateRemindersVisibility();
        populateWhen();
        populateRepeats();
    
private voidpopulateRepeats()

        Time time = mStartTime;
        Resources r = getResources();
        int resource = android.R.layout.simple_spinner_item;

        String[] days = r.getStringArray(R.array.day_labels);
        String[] ordinals = r.getStringArray(R.array.ordinal_labels);

        // Only display "Custom" in the spinner if the device does not support the
        // recurrence functionality of the event. Only display every weekday if
        // the event starts on a weekday.
        boolean isCustomRecurrence = isCustomRecurrence();
        boolean isWeekdayEvent = isWeekdayEvent();

        ArrayList<String> repeatArray = new ArrayList<String>(0);
        ArrayList<Integer> recurrenceIndexes = new ArrayList<Integer>(0);

        repeatArray.add(r.getString(R.string.does_not_repeat));
        recurrenceIndexes.add(DOES_NOT_REPEAT);

        repeatArray.add(r.getString(R.string.daily));
        recurrenceIndexes.add(REPEATS_DAILY);

        if (isWeekdayEvent) {
            repeatArray.add(r.getString(R.string.every_weekday));
            recurrenceIndexes.add(REPEATS_EVERY_WEEKDAY);
        }

        String format = r.getString(R.string.weekly);
        repeatArray.add(String.format(format, time.format("%A")));
        recurrenceIndexes.add(REPEATS_WEEKLY_ON_DAY);

        // Calculate whether this is the 1st, 2nd, 3rd, 4th, or last appearance of the given day.
        int dayNumber = (time.monthDay - 1) / 7;
        format = r.getString(R.string.monthly_on_day_count);
        repeatArray.add(String.format(format, ordinals[dayNumber], days[time.weekDay]));
        recurrenceIndexes.add(REPEATS_MONTHLY_ON_DAY_COUNT);

        format = r.getString(R.string.monthly_on_day);
        repeatArray.add(String.format(format, time.monthDay));
        recurrenceIndexes.add(REPEATS_MONTHLY_ON_DAY);

        long when = time.toMillis(false);
        format = r.getString(R.string.yearly);
        int flags = 0;
        if (DateFormat.is24HourFormat(this)) {
            flags |= DateUtils.FORMAT_24HOUR;
        }
        repeatArray.add(String.format(format, DateUtils.formatDateTime(this, when, flags)));
        recurrenceIndexes.add(REPEATS_YEARLY);

        if (isCustomRecurrence) {
            repeatArray.add(r.getString(R.string.custom));
            recurrenceIndexes.add(REPEATS_CUSTOM);
        }
        mRecurrenceIndexes = recurrenceIndexes;

        int position = recurrenceIndexes.indexOf(DOES_NOT_REPEAT);
        if (mRrule != null) {
            if (isCustomRecurrence) {
                position = recurrenceIndexes.indexOf(REPEATS_CUSTOM);
            } else {
                switch (mEventRecurrence.freq) {
                    case EventRecurrence.DAILY:
                        position = recurrenceIndexes.indexOf(REPEATS_DAILY);
                        break;
                    case EventRecurrence.WEEKLY:
                        if (mEventRecurrence.repeatsOnEveryWeekDay()) {
                            position = recurrenceIndexes.indexOf(REPEATS_EVERY_WEEKDAY);
                        } else {
                            position = recurrenceIndexes.indexOf(REPEATS_WEEKLY_ON_DAY);
                        }
                        break;
                    case EventRecurrence.MONTHLY:
                        if (mEventRecurrence.repeatsMonthlyOnDayCount()) {
                            position = recurrenceIndexes.indexOf(REPEATS_MONTHLY_ON_DAY_COUNT);
                        } else {
                            position = recurrenceIndexes.indexOf(REPEATS_MONTHLY_ON_DAY);
                        }
                        break;
                    case EventRecurrence.YEARLY:
                        position = recurrenceIndexes.indexOf(REPEATS_YEARLY);
                        break;
                }
            }
        }
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, resource, repeatArray);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        mRepeatsSpinner.setAdapter(adapter);
        mRepeatsSpinner.setSelection(position);
    
private voidpopulateWhen()

        long startMillis = mStartTime.toMillis(false /* use isDst */);
        long endMillis = mEndTime.toMillis(false /* use isDst */);
        setDate(mStartDateButton, startMillis);
        setDate(mEndDateButton, endMillis);

        setTime(mStartTimeButton, startMillis);
        setTime(mEndTimeButton, endMillis);

        mStartDateButton.setOnClickListener(new DateClickListener(mStartTime));
        mEndDateButton.setOnClickListener(new DateClickListener(mEndTime));

        mStartTimeButton.setOnClickListener(new TimeClickListener(mStartTime));
        mEndTimeButton.setOnClickListener(new TimeClickListener(mEndTime));
    
static java.util.ArrayListreminderItemsToMinutes(java.util.ArrayList reminderItems, java.util.ArrayList reminderValues)

        int len = reminderItems.size();
        ArrayList<Integer> reminderMinutes = new ArrayList<Integer>(len);
        for (int index = 0; index < len; index++) {
            LinearLayout layout = reminderItems.get(index);
            Spinner spinner = (Spinner) layout.findViewById(R.id.reminder_value);
            int minutes = reminderValues.get(spinner.getSelectedItemPosition());
            reminderMinutes.add(minutes);
        }
        return reminderMinutes;
    
private booleansave()

        boolean forceSaveReminders = false;
        
        // If we are creating a new event, then make sure we wait until the
        // query to fetch the list of calendars has finished.
        if (mEventCursor == null) {
            if (!mCalendarsQueryComplete) {
                // Wait for the calendars query to finish.
                if (mLoadingCalendarsDialog == null) {
                    // Create the progress dialog
                    mLoadingCalendarsDialog = ProgressDialog.show(this,
                            getText(R.string.loading_calendars_title),
                            getText(R.string.loading_calendars_message),
                            true, true, this);
                    mSaveAfterQueryComplete = true;
                }
                return false;
            }

            // Avoid creating a new event if the calendars cursor is empty. This
            // shouldn't ever happen since the setup wizard should ensure the user
            // has a calendar.
            if (mCalendarsCursor == null || mCalendarsCursor.getCount() == 0) {
                Log.w("Cal", "The calendars table does not contain any calendars."
                        + " New event was not created.");
                return true;
            }
            Toast.makeText(this, R.string.creating_event, Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, R.string.saving_event, Toast.LENGTH_SHORT).show();
        }

        ContentResolver cr = getContentResolver();
        ContentValues values = getContentValuesFromUi();
        Uri uri = mUri;

        // For recurring events, we must make sure that we use duration rather
        // than dtend.
        if (uri == null) {
            // Create new event with new contents
            addRecurrenceRule(values);
            uri = cr.insert(Events.CONTENT_URI, values);
            forceSaveReminders = true;

        } else if (mRrule == null) {
            // Modify contents of a non-repeating event
            addRecurrenceRule(values);
            checkTimeDependentFields(values);
            cr.update(uri, values, null, null);
            
        } else if (mInitialValues.getAsString(Events.RRULE) == null) {
            // This event was changed from a non-repeating event to a
            // repeating event.
            addRecurrenceRule(values);
            values.remove(Events.DTEND);
            cr.update(uri, values, null, null);

        } else if (mModification == MODIFY_SELECTED) {
            // Modify contents of the current instance of repeating event

            // Create a recurrence exception
            long begin = mInitialValues.getAsLong(EVENT_BEGIN_TIME);
            values.put(Events.ORIGINAL_EVENT, mEventCursor.getString(EVENT_INDEX_SYNC_ID));
            values.put(Events.ORIGINAL_INSTANCE_TIME, begin);
            boolean allDay = mInitialValues.getAsInteger(Events.ALL_DAY) != 0;
            values.put(Events.ORIGINAL_ALL_DAY, allDay ? 1 : 0);

            uri = cr.insert(Events.CONTENT_URI, values);
            forceSaveReminders = true;

        } else if (mModification == MODIFY_ALL_FOLLOWING) {
            // Modify this instance and all future instances of repeating event
            addRecurrenceRule(values);

            if (mRrule == null) {
                // We've changed a recurring event to a non-recurring event.
                // If the event we are editing is the first in the series,
                // then delete the whole series.  Otherwise, update the series
                // to end at the new start time.
                if (isFirstEventInSeries()) {
                    cr.delete(uri, null, null);
                } else {
                    // Update the current repeating event to end at the new
                    // start time.
                    updatePastEvents(cr, uri);
                }
                uri = cr.insert(Events.CONTENT_URI, values);
            } else {
                if (isFirstEventInSeries()) {
                    checkTimeDependentFields(values);
                    values.remove(Events.DTEND);
                    cr.update(uri, values, null, null);
                } else {
                    // Update the current repeating event to end at the new
                    // start time.
                    updatePastEvents(cr, uri);

                    // Create a new event with the user-modified fields
                    values.remove(Events.DTEND);
                    uri = cr.insert(Events.CONTENT_URI, values);
                }
            }
            forceSaveReminders = true;

        } else if (mModification == MODIFY_ALL) {
            
            // Modify all instances of repeating event
            addRecurrenceRule(values);
            
            if (mRrule == null) {
                // We've changed a recurring event to a non-recurring event.
                // Delete the whole series and replace it with a new
                // non-recurring event.
                cr.delete(uri, null, null);
                uri = cr.insert(Events.CONTENT_URI, values);
                forceSaveReminders = true;
            } else {
                checkTimeDependentFields(values);
                values.remove(Events.DTEND);
                cr.update(uri, values, null, null);
            }
        }

        if (uri != null) {
            long eventId = ContentUris.parseId(uri);
            ArrayList<Integer> reminderMinutes = reminderItemsToMinutes(mReminderItems,
                    mReminderValues);
            saveReminders(cr, eventId, reminderMinutes, mOriginalMinutes,
                    forceSaveReminders);
        }
        return true;
    
static booleansaveReminders(android.content.ContentResolver cr, long eventId, java.util.ArrayList reminderMinutes, java.util.ArrayList originalMinutes, boolean forceSave)
Saves the reminders, if they changed. Returns true if the database was updated.

param
cr the ContentResolver
param
eventId the id of the event whose reminders are being updated
param
reminderMinutes the array of reminders set by the user
param
originalMinutes the original array of reminders
param
forceSave if true, then save the reminders even if they didn't change
return
true if the database was updated

        // If the reminders have not changed, then don't update the database
        if (reminderMinutes.equals(originalMinutes) && !forceSave) {
            return false;
        }

        // Delete all the existing reminders for this event
        String where = Reminders.EVENT_ID + "=?";
        String[] args = new String[] { Long.toString(eventId) };
        cr.delete(Reminders.CONTENT_URI, where, args);

        // Update the "hasAlarm" field for the event
        ContentValues values = new ContentValues();
        int len = reminderMinutes.size();
        values.put(Events.HAS_ALARM, (len > 0) ? 1 : 0);
        Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId);
        cr.update(uri, values, null /* where */, null /* selection args */);

        // Insert the new reminders, if any
        for (int i = 0; i < len; i++) {
            int minutes = reminderMinutes.get(i);

            values.clear();
            values.put(Reminders.MINUTES, minutes);
            values.put(Reminders.METHOD, Reminders.METHOD_ALERT);
            values.put(Reminders.EVENT_ID, eventId);
            cr.insert(Reminders.CONTENT_URI, values);
        }
        return true;
    
private voidsetDate(android.widget.TextView view, long millis)

        int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR |
                DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_MONTH |
                DateUtils.FORMAT_ABBREV_WEEKDAY;
        view.setText(DateUtils.formatDateTime(this, millis, flags));
    
private voidsetTime(android.widget.TextView view, long millis)

        int flags = DateUtils.FORMAT_SHOW_TIME;
        if (DateFormat.is24HourFormat(this)) {
            flags |= DateUtils.FORMAT_24HOUR;
        }
        view.setText(DateUtils.formatDateTime(this, millis, flags));
    
private voidupdatePastEvents(android.content.ContentResolver cr, android.net.Uri uri)

        long oldStartMillis = mEventCursor.getLong(EVENT_INDEX_DTSTART);
        String oldDuration = mEventCursor.getString(EVENT_INDEX_DURATION);
        boolean allDay = mEventCursor.getInt(EVENT_INDEX_ALL_DAY) != 0;
        String oldRrule = mEventCursor.getString(EVENT_INDEX_RRULE);
        mEventRecurrence.parse(oldRrule);

        Time untilTime = new Time();
        long begin = mInitialValues.getAsLong(EVENT_BEGIN_TIME);
        ContentValues oldValues = new ContentValues();

        // The "until" time must be in UTC time in order for Google calendar
        // to display it properly.  For all-day events, the "until" time string
        // must include just the date field, and not the time field.  The
        // repeating events repeat up to and including the "until" time.
        untilTime.timezone = Time.TIMEZONE_UTC;
        
        // Subtract one second from the old begin time to get the new
        // "until" time.
        untilTime.set(begin - 1000);  // subtract one second (1000 millis) 
        if (allDay) {
            untilTime.hour = 0;
            untilTime.minute = 0;
            untilTime.second = 0;
            untilTime.allDay = true;
            untilTime.normalize(false);
            
            // For all-day events, the duration must be in days, not seconds.
            // Otherwise, Google Calendar will (mistakenly) change this event
            // into a non-all-day event.
            int len = oldDuration.length();
            if (oldDuration.charAt(0) == 'P" && oldDuration.charAt(len - 1) == 'S") {
                int seconds = Integer.parseInt(oldDuration.substring(1, len - 1));
                int days = (seconds + DAY_IN_SECONDS - 1) / DAY_IN_SECONDS;
                oldDuration = "P" + days + "D";
            }
        }
        mEventRecurrence.until = untilTime.format2445();

        oldValues.put(Events.DTSTART, oldStartMillis);
        oldValues.put(Events.DURATION, oldDuration);
        oldValues.put(Events.RRULE, mEventRecurrence.toString());
        cr.update(uri, oldValues, null, null);
    
private voidupdateRecurrenceRule()

        int position = mRepeatsSpinner.getSelectedItemPosition();
        int selection = mRecurrenceIndexes.get(position);

        if (selection == DOES_NOT_REPEAT) {
            mRrule = null;
            return;
        } else if (selection == REPEATS_CUSTOM) {
            // Keep custom recurrence as before.
            return;
        } else if (selection == REPEATS_DAILY) {
            mEventRecurrence.freq = EventRecurrence.DAILY;
        } else if (selection == REPEATS_EVERY_WEEKDAY) {
            mEventRecurrence.freq = EventRecurrence.WEEKLY;
            int dayCount = 5;
            int[] byday = new int[dayCount];
            int[] bydayNum = new int[dayCount];

            byday[0] = EventRecurrence.MO;
            byday[1] = EventRecurrence.TU;
            byday[2] = EventRecurrence.WE;
            byday[3] = EventRecurrence.TH;
            byday[4] = EventRecurrence.FR;
            for (int day = 0; day < dayCount; day++) {
                bydayNum[day] = 0;
            }

            mEventRecurrence.byday = byday;
            mEventRecurrence.bydayNum = bydayNum;
            mEventRecurrence.bydayCount = dayCount;
        } else if (selection == REPEATS_WEEKLY_ON_DAY) {
            mEventRecurrence.freq = EventRecurrence.WEEKLY;
            int[] days = new int[1];
            int dayCount = 1;
            int[] dayNum = new int[dayCount];

            days[0] = EventRecurrence.timeDay2Day(mStartTime.weekDay);
            // not sure why this needs to be zero, but set it for now.
            dayNum[0] = 0;

            mEventRecurrence.byday = days;
            mEventRecurrence.bydayNum = dayNum;
            mEventRecurrence.bydayCount = dayCount;
        } else if (selection == REPEATS_MONTHLY_ON_DAY) {
            mEventRecurrence.freq = EventRecurrence.MONTHLY;
            mEventRecurrence.bydayCount = 0;
            mEventRecurrence.bymonthdayCount = 1;
            int[] bymonthday = new int[1];
            bymonthday[0] = mStartTime.monthDay;
            mEventRecurrence.bymonthday = bymonthday;
        } else if (selection == REPEATS_MONTHLY_ON_DAY_COUNT) {
            mEventRecurrence.freq = EventRecurrence.MONTHLY;
            mEventRecurrence.bydayCount = 1;
            mEventRecurrence.bymonthdayCount = 0;

            int[] byday = new int[1];
            int[] bydayNum = new int[1];
            // Compute the week number (for example, the "2nd" Monday)
            int dayCount = 1 + ((mStartTime.monthDay - 1) / 7);
            if (dayCount == 5) {
                dayCount = -1;
            }
            bydayNum[0] = dayCount;
            byday[0] = EventRecurrence.timeDay2Day(mStartTime.weekDay);
            mEventRecurrence.byday = byday;
            mEventRecurrence.bydayNum = bydayNum;
        } else if (selection == REPEATS_YEARLY) {
            mEventRecurrence.freq = EventRecurrence.YEARLY;
        }

        // Set the week start day.
        mEventRecurrence.wkst = EventRecurrence.calendarDay2Day(mFirstDayOfWeek);
        mRrule = mEventRecurrence.toString();
    
private voidupdateRemindersVisibility()

        if (mReminderItems.size() == 0) {
            mRemindersSeparator.setVisibility(View.GONE);
            mRemindersContainer.setVisibility(View.GONE);
        } else {
            mRemindersSeparator.setVisibility(View.VISIBLE);
            mRemindersContainer.setVisibility(View.VISIBLE);
        }