EditEventpublic 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_DAYThis 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 | mSyncIdIf 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 |
Methods Summary |
---|
static void | addMinutesToList(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 void | addRecurrenceRule(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 boolean | addReminder(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 void | addReminder()
// 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 void | checkTimeDependentFields(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.String | constructReminderLabel(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 int | findMinutesInReminderList(java.util.ArrayList values, int minutes)Finds the index of the given "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.ContentValues | getContentValuesFromUi()
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 void | initFromIntent(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 boolean | isCustomRecurrence()
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 boolean | isEmpty()
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 boolean | isFirstEventInSeries()
int dtStart = mEventCursor.getColumnIndexOrThrow(Events.DTSTART);
long start = mEventCursor.getLong(dtStart);
return start == mStartTime.toMillis(true);
| private boolean | isWeekdayEvent()
if (mStartTime.weekDay != Time.SUNDAY && mStartTime.weekDay != Time.SATURDAY) {
return true;
}
return false;
| public void | onCancel(android.content.DialogInterface dialog)
if (dialog == mLoadingCalendarsDialog) {
mSaveAfterQueryComplete = false;
} else if (dialog == mNoCalendarsDialog) {
finish();
}
| public void | onClick(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 void | onClick(android.content.DialogInterface dialog, int which)
if (dialog == mNoCalendarsDialog) {
finish();
}
| protected void | onCreate(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 boolean | onCreateOptionsMenu(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 boolean | onKeyDown(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 boolean | onOptionsItemSelected(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 boolean | onPrepareOptionsMenu(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 void | onResume()
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 void | populateRepeats()
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 void | populateWhen()
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.ArrayList | reminderItemsToMinutes(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 boolean | save()
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 boolean | saveReminders(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.
// 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 void | setDate(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 void | setTime(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 void | updatePastEvents(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 void | updateRecurrenceRule()
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 void | updateRemindersVisibility()
if (mReminderItems.size() == 0) {
mRemindersSeparator.setVisibility(View.GONE);
mRemindersContainer.setVisibility(View.GONE);
} else {
mRemindersSeparator.setVisibility(View.VISIBLE);
mRemindersContainer.setVisibility(View.VISIBLE);
}
|
|