import static android.provider.Calendar.EVENT_BEGIN_TIME;
import static android.provider.Calendar.EVENT_END_TIME;
+import static android.provider.Calendar.AttendeesColumns.ATTENDEE_STATUS;
import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.AsyncQueryHandler;
+import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
import android.content.Intent;
+import android.content.OperationApplicationException;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.PorterDuff;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
+import android.os.RemoteException;
+import android.pim.ContactsAsyncHelper;
import android.pim.EventRecurrence;
import android.preference.PreferenceManager;
import android.provider.Calendar;
+import android.provider.Contacts;
import android.provider.Calendar.Attendees;
import android.provider.Calendar.Calendars;
import android.provider.Calendar.Events;
import android.provider.Calendar.Reminders;
+import android.provider.Contacts.ContactMethods;
+import android.provider.Contacts.Intents;
+import android.provider.Contacts.People;
+import android.provider.Contacts.Presence;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.text.format.Time;
+import android.text.util.Linkify;
+import android.text.util.Rfc822Token;
+import android.util.Log;
import android.view.KeyEvent;
+import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnTouchListener;
+import android.widget.AdapterView;
import android.widget.ArrayAdapter;
+import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
+import android.widget.Toast;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.TimeZone;
+import java.util.regex.Pattern;
-public class EventInfoActivity extends Activity implements View.OnClickListener {
+public class EventInfoActivity extends Activity implements View.OnClickListener,
+ AdapterView.OnItemSelectedListener {
private static final int MAX_REMINDERS = 5;
+ /**
+ * These are the corresponding indices into the array of strings
+ * "R.array.change_response_labels" in the resource file.
+ */
+ static final int UPDATE_SINGLE = 0;
+ static final int UPDATE_ALL = 1;
+
private static final String[] EVENT_PROJECTION = new String[] {
- Events._ID, // 0 do not remove; used in DeleteEventHelper
- Events.TITLE, // 1 do not remove; used in DeleteEventHelper
- Events.RRULE, // 2 do not remove; used in DeleteEventHelper
- Events.ALL_DAY, // 3 do not remove; used in DeleteEventHelper
- Events.CALENDAR_ID, // 4 do not remove; used in DeleteEventHelper
- Events.DTSTART, // 5 do not remove; used in DeleteEventHelper
- Events._SYNC_ID, // 6 do not remove; used in DeleteEventHelper
- Events.EVENT_TIMEZONE, // 7 do not remove; used in DeleteEventHelper
- Events.DESCRIPTION, // 8
- Events.EVENT_LOCATION, // 9
- Events.HAS_ALARM, // 10
- Events.ACCESS_LEVEL, // 11
- Events.COLOR, // 12
+ Events._ID, // 0 do not remove; used in DeleteEventHelper
+ Events.TITLE, // 1 do not remove; used in DeleteEventHelper
+ Events.RRULE, // 2 do not remove; used in DeleteEventHelper
+ Events.ALL_DAY, // 3 do not remove; used in DeleteEventHelper
+ Events.CALENDAR_ID, // 4 do not remove; used in DeleteEventHelper
+ Events.DTSTART, // 5 do not remove; used in DeleteEventHelper
+ Events._SYNC_ID, // 6 do not remove; used in DeleteEventHelper
+ Events.EVENT_TIMEZONE, // 7 do not remove; used in DeleteEventHelper
+ Events.DESCRIPTION, // 8
+ Events.EVENT_LOCATION, // 9
+ Events.HAS_ALARM, // 10
+ Events.ACCESS_LEVEL, // 11
+ Events.COLOR, // 12
};
private static final int EVENT_INDEX_ID = 0;
private static final int EVENT_INDEX_TITLE = 1;
private static final int EVENT_INDEX_RRULE = 2;
private static final int EVENT_INDEX_ALL_DAY = 3;
private static final int EVENT_INDEX_CALENDAR_ID = 4;
+ private static final int EVENT_INDEX_SYNC_ID = 6;
private static final int EVENT_INDEX_EVENT_TIMEZONE = 7;
private static final int EVENT_INDEX_DESCRIPTION = 8;
private static final int EVENT_INDEX_EVENT_LOCATION = 9;
private static final String[] ATTENDEES_PROJECTION = new String[] {
Attendees._ID, // 0
- Attendees.ATTENDEE_RELATIONSHIP, // 1
- Attendees.ATTENDEE_STATUS, // 2
+ Attendees.ATTENDEE_NAME, // 1
+ Attendees.ATTENDEE_EMAIL, // 2
+ Attendees.ATTENDEE_RELATIONSHIP, // 3
+ Attendees.ATTENDEE_STATUS, // 4
};
- private static final int ATTENDEES_INDEX_RELATIONSHIP = 1;
- private static final int ATTENDEES_INDEX_STATUS = 2;
+ private static final int ATTENDEES_INDEX_ID = 0;
+ private static final int ATTENDEES_INDEX_NAME = 1;
+ private static final int ATTENDEES_INDEX_EMAIL = 2;
+ private static final int ATTENDEES_INDEX_RELATIONSHIP = 3;
+ private static final int ATTENDEES_INDEX_STATUS = 4;
+
private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=%d";
- private static final String[] CALENDARS_PROJECTION = new String[] {
- Calendars._ID, // 0
- Calendars.DISPLAY_NAME, // 1
+ static final String[] CALENDARS_PROJECTION = new String[] {
+ Calendars._ID, // 0
+ Calendars.DISPLAY_NAME, // 1
+ Calendars.OWNER_ACCOUNT, // 2
};
- private static final int CALENDARS_INDEX_DISPLAY_NAME = 1;
- private static final String CALENDARS_WHERE = Calendars._ID + "=%d";
+ static final int CALENDARS_INDEX_DISPLAY_NAME = 1;
+ static final int CALENDARS_INDEX_OWNER_ACCOUNT = 2;
+
+ static final String CALENDARS_WHERE = Calendars._ID + "=%d";
private static final String[] REMINDERS_PROJECTION = new String[] {
Reminders._ID, // 0
private int mDefaultReminderMinutes;
private DeleteEventHelper mDeleteEventHelper;
+ private EditResponseHelper mEditResponseHelper;
private int mResponseOffset;
+ private int mOriginalAttendeeResponse;
+ private int mAttendeeResponseFromIntent = ATTENDEE_NO_RESPONSE;
+ private boolean mIsRepeating;
+
+ private Pattern mWildcardPattern = Pattern.compile("^.*$");
+ private LayoutInflater mLayoutInflater;
+
+ private static class ViewHolder {
+ ImageView avatar;
+ ImageView presence;
+ }
+ private HashMap<String, ViewHolder> mPresenceStatuses = new HashMap<String, ViewHolder>();
+ private PresenceQueryHandler mPresenceQueryHandler;
+
+ static final String[] PEOPLE_PROJECTION = new String[] {
+ People._ID,
+ };
+
+ Uri CONTACT_PRESENCE_URI = Uri.withAppendedPath(Contacts.ContactMethods.CONTENT_URI,
+ "with_presence");
+ int PRESENCE_PROJECTION_EMAIL_INDEX = 1;
+ int PRESENCE_PROJECTION_PRESENCE_INDEX = 2;
+ private static final String[] PRESENCE_PROJECTION = new String[] {
+ ContactMethods._ID, // 0
+ ContactMethods.DATA, // 1
+ People.PRESENCE_STATUS, // 2
+ };
+
+ ArrayList<Attendee> mAcceptedAttendees = new ArrayList<Attendee>();
+ ArrayList<Attendee> mDeclinedAttendees = new ArrayList<Attendee>();
+ ArrayList<Attendee> mTentativeAttendees = new ArrayList<Attendee>();
+ private OnClickListener contactOnClickListener = new OnClickListener() {
+ public void onClick(View v) {
+ Attendee attendee = (Attendee) v.getTag();
+ Rect rect = new Rect();
+ v.getDrawingRect(rect);
+ showContactInfo(attendee, rect);
+ }
+ };
+ private int mColor;
+ private String mCalendarOwnerAccount = "";
// This is called when one of the "remove reminder" buttons is selected.
public void onClick(View v) {
updateRemindersVisibility();
}
+ public void onItemSelected(AdapterView parent, View v, int position, long id) {
+ // If they selected the "No response" option, then don't display the
+ // dialog asking which events to change.
+ if (id == 0 && mResponseOffset == 0) {
+ return;
+ }
+
+ // If this is not a repeating event, then don't display the dialog
+ // asking which events to change.
+ if (!mIsRepeating) {
+ return;
+ }
+
+ // If the selection is the same as the original, then don't display the
+ // dialog asking which events to change.
+ int index = findResponseIndexFor(mOriginalAttendeeResponse);
+ if (position == index + mResponseOffset) {
+ return;
+ }
+
+ // This is a repeating event. We need to ask the user if they mean to
+ // change just this one instance or all instances.
+ mEditResponseHelper.showDialog(mEditResponseHelper.getWhichEvents());
+ }
+
+ public void onNothingSelected(AdapterView parent) {
+ }
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
ContentResolver cr = getContentResolver();
mStartMillis = intent.getLongExtra(EVENT_BEGIN_TIME, 0);
mEndMillis = intent.getLongExtra(EVENT_END_TIME, 0);
+ mAttendeeResponseFromIntent = intent.getIntExtra(ATTENDEE_STATUS, ATTENDEE_NO_RESPONSE);
mEventCursor = managedQuery(mUri, EVENT_PROJECTION, null, null);
if (initEventCursor()) {
// The cursor is empty. This can happen if the event was deleted.
Uri uri = Attendees.CONTENT_URI;
String where = String.format(ATTENDEES_WHERE, mEventId);
mAttendeesCursor = managedQuery(uri, ATTENDEES_PROJECTION, where, null);
- initAttendeesCursor();
// Calendars cursor
uri = Calendars.CONTENT_URI;
mCalendarsCursor = managedQuery(uri, CALENDARS_PROJECTION, where, null);
initCalendarsCursor();
- Resources res = getResources();
-
- if (mVisibility >= Calendars.CONTRIBUTOR_ACCESS &&
- mRelationship == Attendees.RELATIONSHIP_ATTENDEE) {
- setTitle(res.getString(R.string.event_info_title_invite));
- } else {
- setTitle(res.getString(R.string.event_info_title));
- }
-
// Initialize the reminder values array.
Resources r = getResources();
String[] strings = r.getStringArray(R.array.reminder_minutes_values);
prefs.getString(CalendarPreferenceActivity.KEY_DEFAULT_REMINDER, "0");
mDefaultReminderMinutes = Integer.parseInt(durationString);
- mRemindersContainer = (LinearLayout) findViewById(R.id.reminders_container);
+ mRemindersContainer = (LinearLayout) findViewById(R.id.reminder_items_container);
// Reminders cursor
boolean hasAlarm = mEventCursor.getInt(EVENT_INDEX_HAS_ALARM) != 0;
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()) {
updateView();
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 */);
+ mEditResponseHelper = new EditResponseHelper(this);
+
+ mPresenceQueryHandler = new PresenceQueryHandler(this, cr);
+ mLayoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
}
initAttendeesCursor();
initCalendarsCursor();
+ updateResponse();
+ updateTitle();
+ }
+
+ private void updateTitle() {
+ Resources res = getResources();
+ if (mVisibility >= Calendars.CONTRIBUTOR_ACCESS &&
+ mRelationship == Attendees.RELATIONSHIP_ATTENDEE) {
+ setTitle(res.getString(R.string.event_info_title_invite));
+ } else {
+ setTitle(res.getString(R.string.event_info_title));
+ }
}
/**
mEventCursor.moveToFirst();
mVisibility = mEventCursor.getInt(EVENT_INDEX_ACCESS_LEVEL);
mEventId = mEventCursor.getInt(EVENT_INDEX_ID);
+ String rRule = mEventCursor.getString(EVENT_INDEX_RRULE);
+ mIsRepeating = (rRule != null);
return false;
}
+ private static class Attendee {
+ String mName;
+ String mEmail;
+
+ Attendee(String name, String email) {
+ mName = name;
+ mEmail = email;
+ }
+ }
+
private void initAttendeesCursor() {
if (mAttendeesCursor != null) {
if (mAttendeesCursor.moveToFirst()) {
- mRelationship = mAttendeesCursor.getInt(ATTENDEES_INDEX_RELATIONSHIP);
+ mAcceptedAttendees.clear();
+ mDeclinedAttendees.clear();
+ mTentativeAttendees.clear();
+
+ do {
+ int status = mAttendeesCursor.getInt(ATTENDEES_INDEX_STATUS);
+ String name = mAttendeesCursor.getString(ATTENDEES_INDEX_NAME);
+ String email = mAttendeesCursor.getString(ATTENDEES_INDEX_EMAIL);
+ int relationship = mAttendeesCursor.getInt(ATTENDEES_INDEX_RELATIONSHIP);
+ if (mRelationship != relationship && mCalendarOwnerAccount.equals(email)) {
+ mRelationship = relationship;
+ }
+
+ switch(status) {
+ case Attendees.ATTENDEE_STATUS_ACCEPTED:
+ mAcceptedAttendees.add(new Attendee(name, email));
+ break;
+ case Attendees.ATTENDEE_STATUS_DECLINED:
+ mDeclinedAttendees.add(new Attendee(name, email));
+ break;
+ default:
+ mTentativeAttendees.add(new Attendee(name, email));
+ }
+ } while (mAttendeesCursor.moveToNext());
+ mAttendeesCursor.moveToFirst();
+
+ updateAttendees();
}
}
+
+ // TODO We shouldn't have to guess whether the current user is the organizer or not
+ if (mVisibility < Calendars.CONTRIBUTOR_ACCESS
+ && mRelationship == Attendees.RELATIONSHIP_ORGANIZER) {
+ mRelationship = Attendees.RELATIONSHIP_ATTENDEE;
+ }
}
private void initCalendarsCursor() {
@Override
public void onPause() {
super.onPause();
+ if (!isFinishing()) {
+ return;
+ }
ContentResolver cr = getContentResolver();
ArrayList<Integer> reminderMinutes = EditEvent.reminderItemsToMinutes(mReminderItems,
mReminderValues);
- EditEvent.saveReminders(cr, mEventId, reminderMinutes, mOriginalMinutes);
- saveResponse();
+ ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(3);
+ boolean changed = EditEvent.saveReminders(ops, mEventId, reminderMinutes, mOriginalMinutes,
+ false /* no force save */);
+ try {
+ cr.applyBatch(Calendars.CONTENT_URI.getAuthority(), ops);
+ } catch (RemoteException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (OperationApplicationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ changed |= saveResponse(cr);
+ if (changed) {
+ Toast.makeText(this, R.string.saving_event, Toast.LENGTH_SHORT).show();
+ }
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Cannot add reminders to a shared calendar with only free/busy
// permissions
- if (mVisibility >= Calendars.READ_ACCESS && 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);
- }
+ boolean canAddReminders =
+ mVisibility >= Calendars.READ_ACCESS && mReminderItems.size() < MAX_REMINDERS;
+ menu.setGroupVisible(MENU_GROUP_REMINDER, canAddReminders);
+ menu.setGroupEnabled(MENU_GROUP_REMINDER, canAddReminders);
+
+ boolean canModifyCalendar = mVisibility >= Calendars.CONTRIBUTOR_ACCESS;
+ boolean canModifyEvent = canModifyCalendar
+ && mRelationship >= Attendees.RELATIONSHIP_ORGANIZER;
+ menu.setGroupVisible(MENU_GROUP_EDIT, canModifyEvent);
+ menu.setGroupEnabled(MENU_GROUP_EDIT, canModifyEvent);
+ menu.setGroupVisible(MENU_GROUP_DELETE, canModifyCalendar);
+ menu.setGroupEnabled(MENU_GROUP_DELETE, canModifyCalendar);
- if (mVisibility >= Calendars.CONTRIBUTOR_ACCESS &&
- mRelationship >= Attendees.RELATIONSHIP_ORGANIZER) {
- menu.setGroupVisible(MENU_GROUP_EDIT, true);
- menu.setGroupEnabled(MENU_GROUP_EDIT, true);
- menu.setGroupVisible(MENU_GROUP_DELETE, true);
- menu.setGroupEnabled(MENU_GROUP_DELETE, true);
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ private void addReminder() {
+ // TODO: when adding a new reminder, make it different from the
+ // last one in the list (if any).
+ if (mDefaultReminderMinutes == 0) {
+ EditEvent.addReminder(this, this, mReminderItems,
+ mReminderValues, mReminderLabels, 10 /* minutes */);
} else {
- menu.setGroupVisible(MENU_GROUP_EDIT, false);
- menu.setGroupEnabled(MENU_GROUP_EDIT, false);
- menu.setGroupVisible(MENU_GROUP_DELETE, false);
- menu.setGroupEnabled(MENU_GROUP_DELETE, false);
+ EditEvent.addReminder(this, this, mReminderItems,
+ mReminderValues, mReminderLabels, mDefaultReminderMinutes);
}
-
- return super.onPrepareOptionsMenu(menu);
+ updateRemindersVisibility();
}
@Override
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case MENU_ADD_REMINDER:
- // TODO: when adding a new reminder, make it different from the
- // last one in the list (if any).
- if (mDefaultReminderMinutes == 0) {
- EditEvent.addReminder(this, this, mReminderItems,
- mReminderValues, mReminderLabels, 10 /* minutes */);
- } else {
- EditEvent.addReminder(this, this, mReminderItems,
- mReminderValues, mReminderLabels, mDefaultReminderMinutes);
- }
- updateRemindersVisibility();
+ addReminder();
break;
case MENU_EDIT:
doEdit();
}
}
- private void saveResponse() {
- if (mAttendeesCursor == null) {
- return;
+ /**
+ * Saves the response to an invitation if the user changed the response.
+ * Returns true if the database was updated.
+ *
+ * @param cr the ContentResolver
+ * @return true if the database was changed
+ */
+ private boolean saveResponse(ContentResolver cr) {
+ if (mAttendeesCursor == null || mEventCursor == null) {
+ return false;
}
Spinner spinner = (Spinner) findViewById(R.id.response_value);
int position = spinner.getSelectedItemPosition() - mResponseOffset;
if (position <= 0) {
- return;
+ return false;
}
int status = ATTENDEE_VALUES[position];
- mAttendeesCursor.updateInt(ATTENDEES_INDEX_STATUS, status);
- mAttendeesCursor.commitUpdates();
+
+ // If the status has not changed, then don't update the database
+ if (status == mOriginalAttendeeResponse) {
+ return false;
+ }
+
+ // TODO find the right row first
+ long attendeeId = mAttendeesCursor.getInt(ATTENDEES_INDEX_ID);
+ if (!mIsRepeating) {
+ // This is a non-repeating event
+ updateResponse(cr, mEventId, attendeeId, status);
+ return true;
+ }
+
+ // This is a repeating event
+ int whichEvents = mEditResponseHelper.getWhichEvents();
+ switch (whichEvents) {
+ case -1:
+ return false;
+ case UPDATE_SINGLE:
+ createExceptionResponse(cr, mEventId, attendeeId, status);
+ return true;
+ case UPDATE_ALL:
+ updateResponse(cr, mEventId, attendeeId, status);
+ return true;
+ default:
+ Log.e("Calendar", "Unexpected choice for updating invitation response");
+ break;
+ }
+ return false;
+ }
+
+ private void updateResponse(ContentResolver cr, long eventId, long attendeeId, int status) {
+ // Update the "selfAttendeeStatus" field for the event
+ ContentValues values = new ContentValues();
+
+ // Will need to add email when MULTIPLE_ATTENDEES_PER_EVENT supported.
+ values.put(Attendees.ATTENDEE_STATUS, status);
+ values.put(Attendees.EVENT_ID, eventId);
+
+ Uri uri = ContentUris.withAppendedId(Attendees.CONTENT_URI, attendeeId);
+ cr.update(uri, values, null /* where */, null /* selection args */);
+ }
+
+ private void createExceptionResponse(ContentResolver cr, long eventId,
+ long attendeeId, int status) {
+ // Fetch information about the repeating event.
+ Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId);
+ Cursor cursor = cr.query(uri, EVENT_PROJECTION, null, null, null);
+ if (cursor == null) {
+ return;
+ }
+
+ try {
+ cursor.moveToFirst();
+ ContentValues values = new ContentValues();
+
+ String title = cursor.getString(EVENT_INDEX_TITLE);
+ String timezone = cursor.getString(EVENT_INDEX_EVENT_TIMEZONE);
+ int calendarId = cursor.getInt(EVENT_INDEX_CALENDAR_ID);
+ boolean allDay = cursor.getInt(EVENT_INDEX_ALL_DAY) != 0;
+ String syncId = cursor.getString(EVENT_INDEX_SYNC_ID);
+
+ values.put(Events.TITLE, title);
+ values.put(Events.EVENT_TIMEZONE, timezone);
+ values.put(Events.ALL_DAY, allDay ? 1 : 0);
+ values.put(Events.CALENDAR_ID, calendarId);
+ values.put(Events.DTSTART, mStartMillis);
+ values.put(Events.DTEND, mEndMillis);
+ values.put(Events.ORIGINAL_EVENT, syncId);
+ values.put(Events.ORIGINAL_INSTANCE_TIME, mStartMillis);
+ values.put(Events.ORIGINAL_ALL_DAY, allDay ? 1 : 0);
+ values.put(Events.STATUS, Events.STATUS_CONFIRMED);
+ values.put(Events.SELF_ATTENDEE_STATUS, status);
+
+ // Create a recurrence exception
+ cr.insert(Events.CONTENT_URI, values);
+ } finally {
+ cursor.close();
+ }
}
private int findResponseIndexFor(int response) {
return;
}
Resources res = getResources();
- ContentResolver cr = getContentResolver();
String eventName = mEventCursor.getString(EVENT_INDEX_TITLE);
if (eventName == null || eventName.length() == 0) {
String rRule = mEventCursor.getString(EVENT_INDEX_RRULE);
boolean hasAlarm = mEventCursor.getInt(EVENT_INDEX_HAS_ALARM) != 0;
String eventTimezone = mEventCursor.getString(EVENT_INDEX_EVENT_TIMEZONE);
- int color = mEventCursor.getInt(EVENT_INDEX_COLOR) & 0xbbffffff;
+ mColor = mEventCursor.getInt(EVENT_INDEX_COLOR) & 0xbbffffff;
+
+ View calBackground = findViewById(R.id.cal_background);
+ calBackground.setBackgroundColor(mColor);
- ImageView stripe = (ImageView) findViewById(R.id.vertical_stripe);
- stripe.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_IN);
+ TextView title = (TextView) findViewById(R.id.title);
+ title.setTextColor(mColor);
+
+ View divider = findViewById(R.id.divider);
+ divider.getBackground().setColorFilter(mColor, PorterDuff.Mode.SRC_IN);
// What
if (eventName != null) {
localTimezone = Time.TIMEZONE_UTC;
}
if (eventTimezone != null && !localTimezone.equals(eventTimezone) && !allDay) {
- setTextCommon(R.id.timezone, localTimezone);
+ String displayName;
+ TimeZone tz = TimeZone.getTimeZone(localTimezone);
+ if (tz == null || tz.getID().equals("GMT")) {
+ displayName = localTimezone;
+ } else {
+ displayName = tz.getDisplayName();
+ }
+
+ setTextCommon(R.id.timezone, displayName);
} else {
setVisibilityCommon(R.id.timezone_container, View.GONE);
}
if (location == null || location.length() == 0) {
setVisibilityCommon(R.id.where, View.GONE);
} else {
- setTextCommon(R.id.where, location);
+ final TextView textView = (TextView) findViewById(R.id.where);
+ if (textView != null) {
+ textView.setAutoLinkMask(0);
+ textView.setText(location);
+ Linkify.addLinks(textView, mWildcardPattern, "geo:0,0?q=");
+ textView.setOnTouchListener(new OnTouchListener() {
+ public boolean onTouch(View v, MotionEvent event) {
+ try {
+ return v.onTouchEvent(event);
+ } catch (ActivityNotFoundException e) {
+ // ignore
+ return true;
+ }
+ }
+ });
+ }
}
// Description
mCalendarsCursor.moveToFirst();
String calendarName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
setTextCommon(R.id.calendar, calendarName);
+ mCalendarOwnerAccount = mCalendarsCursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
} else {
setVisibilityCommon(R.id.calendar_container, View.GONE);
}
+ }
- // Response
- updateResponse();
+ private void updateAttendees() {
+ CharSequence[] entries;
+ entries = getResources().getTextArray(R.array.response_labels2);
+ LinearLayout attendeesLayout = (LinearLayout) findViewById(R.id.attendee_list);
+ attendeesLayout.removeAllViewsInLayout();
+ addAttendeesToLayout(mAcceptedAttendees, attendeesLayout, entries[0]);
+ addAttendeesToLayout(mDeclinedAttendees, attendeesLayout, entries[2]);
+ addAttendeesToLayout(mTentativeAttendees, attendeesLayout, entries[1]);
+ }
+
+ private void addAttendeesToLayout(ArrayList<Attendee> attendees, LinearLayout attendeeList,
+ CharSequence sectionTitle) {
+ if (attendees.size() == 0) {
+ return;
+ }
+
+ ContentResolver cr = getContentResolver();
+ // Yes/No/Maybe Title
+ View titleView = mLayoutInflater.inflate(R.layout.contact_item, null);
+ titleView.findViewById(R.id.avatar).setVisibility(View.GONE);
+ View divider = titleView.findViewById(R.id.separator);
+ divider.getBackground().setColorFilter(mColor, PorterDuff.Mode.SRC_IN);
+
+ TextView title = (TextView) titleView.findViewById(R.id.name);
+ title.setText(getString(R.string.response_label, sectionTitle, attendees.size()));
+ title.setTextAppearance(this, R.style.TextAppearance_EventInfo_Label);
+ attendeeList.addView(titleView);
+
+ // Attendees
+ int numOfAttendees = attendees.size();
+ StringBuilder selection = new StringBuilder(Contacts.ContactMethods.DATA + " IN (");
+ String[] selectionArgs = new String[numOfAttendees];
+
+ for (int i = 0; i < numOfAttendees; ++i) {
+ Attendee attendee = attendees.get(i);
+ selectionArgs[i] = attendee.mEmail;
+
+ View v = mLayoutInflater.inflate(R.layout.contact_item, null);
+ v.setOnClickListener(contactOnClickListener);
+ v.setTag(attendee);
+
+ View separator = v.findViewById(R.id.separator);
+ separator.getBackground().setColorFilter(mColor, PorterDuff.Mode.SRC_IN);
+
+ // Text
+ TextView tv = (TextView) v.findViewById(R.id.name);
+ String name = attendee.mName;
+ if (name == null || name.length() == 0) {
+ name = attendee.mEmail;
+ }
+ tv.setText(name);
+
+ ViewHolder vh = new ViewHolder();
+ vh.avatar = (ImageView) v.findViewById(R.id.avatar);
+ vh.presence = (ImageView) v.findViewById(R.id.presence);
+ mPresenceStatuses.put(attendee.mEmail, vh);
+
+ if (i == 0) {
+ selection.append('?');
+ } else {
+ selection.append(", ?");
+ }
+
+ attendeeList.addView(v);
+ }
+ selection.append(')');
+
+ mPresenceQueryHandler.startQuery(0, attendees, CONTACT_PRESENCE_URI, PRESENCE_PROJECTION,
+ selection.toString(), selectionArgs, null);
+ }
+
+ private class PresenceQueryHandler extends AsyncQueryHandler {
+ Context mContext;
+ ContentResolver mContentResolver;
+
+ public PresenceQueryHandler(Context context, ContentResolver cr) {
+ super(cr);
+ mContentResolver = cr;
+ mContext = context;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
+ cursor.moveToPosition(-1);
+ while (cursor.moveToNext()) {
+ String email = cursor.getString(PRESENCE_PROJECTION_EMAIL_INDEX);
+ ViewHolder vh = mPresenceStatuses.get(email);
+ ImageView presenceView = vh.presence;
+ if (presenceView != null) {
+ int status = cursor.getInt(PRESENCE_PROJECTION_PRESENCE_INDEX);
+ presenceView.setImageResource(Presence.getPresenceIconResourceId(status));
+ presenceView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ ArrayList<Attendee> attendees = (ArrayList<Attendee>) cookie;
+ for (Attendee attendee : attendees) {
+ Uri uri = Uri.withAppendedPath(People.WITH_EMAIL_OR_IM_FILTER_URI, Uri
+ .encode(attendee.mEmail));
+ // TODO Get rid of this query.
+ Cursor personCursor = mContentResolver.query(uri, PEOPLE_PROJECTION, null, null,
+ null);
+ if (personCursor != null) {
+ if (personCursor.moveToFirst()) {
+ Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI, personCursor
+ .getInt(0));
+ ViewHolder vh = mPresenceStatuses.get(attendee.mEmail);
+ if (vh != null) {
+ ContactsAsyncHelper.updateImageViewWithContactPhotoAsync(mContext,
+ vh.avatar, personUri, -1);
+ }
+ }
+ personCursor.close();
+ }
+ }
+ }
}
void updateResponse() {
Spinner spinner = (Spinner) findViewById(R.id.response_value);
- int response = ATTENDEE_NO_RESPONSE;
+ mOriginalAttendeeResponse = ATTENDEE_NO_RESPONSE;
if (mAttendeesCursor != null) {
- response = mAttendeesCursor.getInt(ATTENDEES_INDEX_STATUS);
+ // TODO find the right row first
+ mOriginalAttendeeResponse = mAttendeesCursor.getInt(ATTENDEES_INDEX_STATUS);
}
mResponseOffset = 0;
* Switch the entries to a set of entries without the
* no response option.
*/
- if ((response != Attendees.ATTENDEE_STATUS_INVITED)
- && (response != ATTENDEE_NO_RESPONSE)
- && (response != Attendees.ATTENDEE_STATUS_NONE)) {
+ if ((mOriginalAttendeeResponse != Attendees.ATTENDEE_STATUS_INVITED)
+ && (mOriginalAttendeeResponse != ATTENDEE_NO_RESPONSE)
+ && (mOriginalAttendeeResponse != Attendees.ATTENDEE_STATUS_NONE)) {
CharSequence[] entries;
entries = getResources().getTextArray(R.array.response_labels2);
mResponseOffset = -1;
spinner.setAdapter(adapter);
}
- int index = findResponseIndexFor(response);
+ int index;
+ if (mAttendeeResponseFromIntent != ATTENDEE_NO_RESPONSE) {
+ index = findResponseIndexFor(mAttendeeResponseFromIntent);
+ } else {
+ index = findResponseIndexFor(mOriginalAttendeeResponse);
+ }
spinner.setSelection(index + mResponseOffset);
+ spinner.setOnItemSelectedListener(this);
}
private void setTextCommon(int id, CharSequence text) {
}
return;
}
+
+ /**
+ * Taken from com.google.android.gm.HtmlConversationActivity
+ *
+ * Send the intent that shows the Contact info corresponding to the email address.
+ */
+ public void showContactInfo(Attendee attendee, Rect rect) {
+ Uri contactUri = Uri.fromParts("mailto", attendee.mEmail, null);
+
+ Intent contactIntent = new Intent(Contacts.Intents.SHOW_OR_CREATE_CONTACT);
+ contactIntent.setData(contactUri);
+
+ // Pass along full E-mail string for possible create dialog
+ Rfc822Token sender = new Rfc822Token(attendee.mName, attendee.mEmail, null);
+ contactIntent.putExtra(Contacts.Intents.EXTRA_CREATE_DESCRIPTION,
+ sender.toString());
+
+ // Mark target position using on-screen coordinates
+ contactIntent.putExtra(Intents.EXTRA_TARGET_RECT, rect);
+
+ // Only provide personal name hint if we have one
+ if (attendee.mName != null && attendee.mName.length() > 0) {
+ contactIntent.putExtra(Intents.Insert.NAME, attendee.mName);
+ }
+
+ startActivity(contactIntent);
+ }
}