summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2015-01-24 07:55:08 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2015-01-24 07:55:08 -0800
commitb8508df0bf9a1ab57c4d339a0fc8e60d55239462 (patch)
treee3d3f10c1b11fa5b37d5592b8b1535b307446328
parent476b55527a1d92fe689dd5debd85ac0a00fb3a1b (diff)
parentc0b844cd8a5209895fdc52d5ffa68bf5b2fc1234 (diff)
downloadandroid_packages_apps_Calendar-b8508df0bf9a1ab57c4d339a0fc8e60d55239462.tar.gz
android_packages_apps_Calendar-b8508df0bf9a1ab57c4d339a0fc8e60d55239462.tar.bz2
android_packages_apps_Calendar-b8508df0bf9a1ab57c4d339a0fc8e60d55239462.zip
Merge "Calendar : Respond to calendar events share intent"
-rw-r--r--AndroidManifest.xml10
-rw-r--r--res/layout/agenda_item.xml19
-rw-r--r--res/menu/share_event_title_bar.xml29
-rw-r--r--res/values/cm_plurals.xml11
-rw-r--r--src/com/android/calendar/CalendarUtils.java77
-rw-r--r--src/com/android/calendar/EventInfoFragment.java251
-rw-r--r--src/com/android/calendar/ShareCalendarActivity.java229
-rw-r--r--src/com/android/calendar/agenda/AgendaAdapter.java3
-rw-r--r--src/com/android/calendar/agenda/AgendaFragment.java33
-rw-r--r--src/com/android/calendar/agenda/AgendaListView.java43
-rw-r--r--src/com/android/calendar/agenda/AgendaWindowAdapter.java60
-rw-r--r--src/com/android/calendar/icalendar/VCalendar.java21
12 files changed, 668 insertions, 118 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index bb4bf3e3..bc36311d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -178,6 +178,16 @@
android:value="com.android.calendar.AllInOneActivity" />
</activity>
+ <activity android:name=".ShareCalendarActivity"
+ android:theme="@style/CalendarTheme.WithActionBar">
+ <intent-filter>
+ <action android:name="android.intent.action.GET_CONTENT"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.APP_CALENDAR" />
+ <data android:mimeType="text/x-vCalendar"/>
+ </intent-filter>
+ </activity>
+
<provider android:name=".CalendarRecentSuggestionsProvider"
android:exported="false"
android:authorities="com.android.calendar.CalendarRecentSuggestionsProvider" />
diff --git a/res/layout/agenda_item.xml b/res/layout/agenda_item.xml
index 16f81506..8d90581f 100644
--- a/res/layout/agenda_item.xml
+++ b/res/layout/agenda_item.xml
@@ -20,7 +20,7 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="64dip"
- android:columnCount="3"
+ android:columnCount="4"
android:rowCount="2">
<View
android:layout_height="1px"
@@ -28,7 +28,7 @@
android:layout_column="0"
android:layout_row="0"
android:layout_rowSpan="1"
- android:layout_columnSpan="3"
+ android:layout_columnSpan="4"
android:layout_width="match_parent" />
<com.android.calendar.ColorChipView
android:id="@+id/agenda_item_color"
@@ -86,9 +86,22 @@
android:textColor="@color/agenda_item_where_text_color"
style="?android:attr/textAppearanceSmallInverse" />
</LinearLayout>
+
+ <CheckBox
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:id="@+id/shareCheckbox"
+ android:layout_row="1"
+ android:layout_column="2"
+ android:layout_rowSpan="1"
+ android:layout_gravity="center_vertical"
+ android:layout_marginRight="10dip"
+ android:focusable="false"
+ android:visibility="gone"/>
+
<ImageView
android:id="@+id/selected_marker"
- android:layout_column="2"
+ android:layout_column="3"
android:layout_row="1"
android:layout_rowSpan="1"
android:layout_width="wrap_content"
diff --git a/res/menu/share_event_title_bar.xml b/res/menu/share_event_title_bar.xml
new file mode 100644
index 00000000..3f8b326c
--- /dev/null
+++ b/res/menu/share_event_title_bar.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<menu
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/action_cancel"
+ android:alphabeticShortcut="c"
+ android:title="@string/discard_label"
+ android:icon="@drawable/ic_menu_cancel_holo_light"
+ android:showAsAction="withText|always" />
+ <item android:id="@+id/action_done"
+ android:alphabeticShortcut="d"
+ android:title="@string/save_label"
+ android:icon="@drawable/ic_menu_done_holo_light"
+ android:showAsAction="withText|always" />
+</menu>
diff --git a/res/values/cm_plurals.xml b/res/values/cm_plurals.xml
index d7caea6f..48fae5ab 100644
--- a/res/values/cm_plurals.xml
+++ b/res/values/cm_plurals.xml
@@ -15,7 +15,16 @@
limitations under the License.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
<plurals name="events_selected">
- <item quantity="other">%1$d selected</item>
+ <item quantity="zero">No events selected</item>
+ <item quantity="one">%1$d event selected</item>
+ <item quantity="other">%1$d events selected</item>
+ </plurals>
+
+ <plurals name="select_events_to_share">
+ <item quantity="one">Select an event to share</item>
+ <item quantity="other">Select events to share</item>
</plurals>
+
</resources>
diff --git a/src/com/android/calendar/CalendarUtils.java b/src/com/android/calendar/CalendarUtils.java
index 0238c321..7b9ffc10 100644
--- a/src/com/android/calendar/CalendarUtils.java
+++ b/src/com/android/calendar/CalendarUtils.java
@@ -103,7 +103,7 @@ public class CalendarUtils {
// Check the values in the db
int keyColumn = cursor.getColumnIndexOrThrow(CalendarCache.KEY);
int valueColumn = cursor.getColumnIndexOrThrow(CalendarCache.VALUE);
- while(cursor.moveToNext()) {
+ while (cursor.moveToNext()) {
String key = cursor.getString(keyColumn);
String value = cursor.getString(valueColumn);
if (TextUtils.equals(key, CalendarCache.KEY_TIMEZONE_TYPE)) {
@@ -353,4 +353,79 @@ public class CalendarUtils {
public static SharedPreferences getSharedPreferences(Context context, String prefsName) {
return context.getSharedPreferences(prefsName, Context.MODE_PRIVATE);
}
+
+ /**
+ * For those interested in changes to the list of shared calendar events
+ */
+ public static interface ShareEventListener {
+
+ /**
+ * Called whenever a calendar event is added to the list of events about to be shared
+ *
+ * @param eventInfo A Triple containing event related information
+ * Triple (event id, startMillis, endMillis)
+ */
+ public void onEventShared(Triple<Long, Long, Long> eventInfo);
+
+
+ /**
+ * called when an event is removed from the share list
+ */
+ public void onEventRemoval(long eventId);
+
+ /**
+ * called to signal that the current share list has been discarded
+ */
+ public void onResetShareList();
+ }
+
+ /**
+ * Implementation of a 3-tuple
+ * Modeled after {@link android.util.Pair} for passing calendar event information
+ *
+ * The first element is perceived to be the unique identifier with the others serving as storage
+ * for ancillary information
+ */
+ public static class Triple<X, Y, Z> {
+ public X first; // dominating element used in equals() and hashCode() implementations
+ public Y second;
+ public Z third;
+
+ public Triple(X a, Y b, Z c) {
+ first = a;
+ second = b;
+ third = c;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("[");
+ builder.append(first.toString());
+ builder.append(" , ");
+ builder.append(second.toString());
+ builder.append(" , ");
+ builder.append(third.toString());
+ builder.append("]");
+ return builder.toString();
+ }
+
+ /**
+ * First element in the triple is used for comparison, as the other are used to store
+ * ancillary information
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Triple)) return false;
+ return ((Triple)o).first.equals(first);
+ }
+
+ /**
+ * Only the first element contributes
+ */
+ @Override
+ public int hashCode() {
+ return first.hashCode();
+ }
+ }
}
diff --git a/src/com/android/calendar/EventInfoFragment.java b/src/com/android/calendar/EventInfoFragment.java
index 4374226e..dd4d17a6 100644
--- a/src/com/android/calendar/EventInfoFragment.java
+++ b/src/com/android/calendar/EventInfoFragment.java
@@ -427,6 +427,10 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
private QueryHandler mHandler;
+ // used to signal the completion of querying calendar event data
+ // note: runnable is executed on the ui thread
+ private Runnable mQueryCompleteRunnable;
+
private final Runnable mTZUpdater = new Runnable() {
@Override
public void run() {
@@ -463,6 +467,8 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
private CalendarController mController;
+ private boolean mInNonUiMode;
+
private class QueryHandler extends AsyncQueryService {
public QueryHandler(Context context) {
super(context);
@@ -471,7 +477,7 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
// if the activity is finishing, then close the cursor and return
- final Activity activity = getActivity();
+ final Activity activity = (mActivity != null) ? mActivity : getActivity();
if (activity == null || activity.isFinishing()) {
if (cursor != null) {
cursor.close();
@@ -517,9 +523,10 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
case TOKEN_QUERY_CALENDARS:
mCalendarsCursor = Utils.matrixCursorFromCursor(cursor);
updateCalendar(mView);
- // FRAG_TODO fragments shouldn't set the title anymore
- updateTitle();
-
+ if (!mInNonUiMode) {
+ // FRAG_TODO fragments shouldn't set the title anymore
+ updateTitle();
+ }
args = new String[] {
mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_NAME),
mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_TYPE) };
@@ -535,7 +542,7 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
startQuery(TOKEN_QUERY_ATTENDEES, null, uri, ATTENDEES_PROJECTION,
ATTENDEES_WHERE, args, ATTENDEES_SORT_ORDER);
} else {
- sendAccessibilityEventIfQueryDone(TOKEN_QUERY_ATTENDEES);
+ assessQueryCompletion(TOKEN_QUERY_ATTENDEES);
}
if (mHasAlarm) {
// start reminders query
@@ -544,10 +551,11 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
startQuery(TOKEN_QUERY_REMINDERS, null, uri,
REMINDERS_PROJECTION, REMINDERS_WHERE, args, null);
} else {
- sendAccessibilityEventIfQueryDone(TOKEN_QUERY_REMINDERS);
+ assessQueryCompletion(TOKEN_QUERY_REMINDERS);
}
break;
case TOKEN_QUERY_COLORS:
+ if (mInNonUiMode) break;
ArrayList<Integer> colors = new ArrayList<Integer>();
if (cursor.moveToFirst()) {
do
@@ -584,11 +592,11 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
case TOKEN_QUERY_ATTENDEES:
mAttendeesCursor = Utils.matrixCursorFromCursor(cursor);
initAttendeesCursor(mView);
- updateResponse(mView);
+ if (!mInNonUiMode) updateResponse(mView);
break;
case TOKEN_QUERY_REMINDERS:
mRemindersCursor = Utils.matrixCursorFromCursor(cursor);
- initReminders(mView, mRemindersCursor);
+ if (!mInNonUiMode) initReminders(mView, mRemindersCursor);
break;
case TOKEN_QUERY_VISIBLE_CALENDARS:
if (cursor.getCount() > 1) {
@@ -601,34 +609,38 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
} else {
// Don't need to display the calendar owner when there is only a single
// calendar. Skip the duplicate calendars query.
- setVisibilityCommon(mView, R.id.calendar_container, View.GONE);
+ if (!mInNonUiMode) {
+ setVisibilityCommon(mView, R.id.calendar_container, View.GONE);
+ }
mCurrentQuery |= TOKEN_QUERY_DUPLICATE_CALENDARS;
}
break;
case TOKEN_QUERY_DUPLICATE_CALENDARS:
- SpannableStringBuilder sb = new SpannableStringBuilder();
-
- // Calendar display name
- String calendarName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
- sb.append(calendarName);
-
- // Show email account if display name is not unique and
- // display name != email
- String email = mCalendarsCursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
- if (cursor.getCount() > 1 && !calendarName.equalsIgnoreCase(email) &&
- Utils.isValidEmail(email)) {
- sb.append(" (").append(email).append(")");
- }
+ if (!mInNonUiMode) {
+ SpannableStringBuilder sb = new SpannableStringBuilder();
+
+ // Calendar display name
+ String calendarName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
+ sb.append(calendarName);
+
+ // Show email account if display name is not unique and
+ // display name != email
+ String email = mCalendarsCursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
+ if (cursor.getCount() > 1 && !calendarName.equalsIgnoreCase(email) &&
+ Utils.isValidEmail(email)) {
+ sb.append(" (").append(email).append(")");
+ }
- setVisibilityCommon(mView, R.id.calendar_container, View.VISIBLE);
- setTextCommon(mView, R.id.calendar_name, sb);
+ setVisibilityCommon(mView, R.id.calendar_container, View.VISIBLE);
+ setTextCommon(mView, R.id.calendar_name, sb);
+ }
break;
}
cursor.close();
- sendAccessibilityEventIfQueryDone(token);
+ assessQueryCompletion(token);
// All queries are done, show the view.
- if (mCurrentQuery == TOKEN_QUERY_ALL) {
+ if (mCurrentQuery == TOKEN_QUERY_ALL && !mInNonUiMode) {
if (mLoadingMsgView.getAlpha() == 1) {
// Loading message is showing, let it stay a bit more (to prevent
// flashing) by adding a start delay to the event animation
@@ -648,10 +660,18 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
}
}
- private void sendAccessibilityEventIfQueryDone(int token) {
+ private void assessQueryCompletion(int token) {
mCurrentQuery |= token;
if (mCurrentQuery == TOKEN_QUERY_ALL) {
- sendAccessibilityEvent();
+
+ // signal query completion
+ if (mQueryCompleteRunnable != null) {
+ mActivity.runOnUiThread(mQueryCompleteRunnable);
+ }
+ if (!mInNonUiMode) {
+ sendAccessibilityEvent();
+ }
+
}
}
@@ -699,6 +719,10 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
mEventId = eventId;
}
+ public void launchInNonUiMode() {
+ mInNonUiMode = true;
+ }
+
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@@ -739,6 +763,10 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
}
}
+ public void setQueryCompleteRunnable(Runnable runnable) {
+ mQueryCompleteRunnable = runnable;
+ }
+
private void applyDialogParams() {
Dialog dialog = getDialog();
dialog.setCanceledOnTouchOutside(true);
@@ -870,6 +898,21 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
}
}
+ /**
+ * Initiate the querying of the calendar event data.
+ * For when this component is started in a non-ui mode
+ */
+ public void startQueryingData(Context context) {
+ mContext = context;
+ if (context instanceof Activity) {
+ mActivity = (Activity) context;
+ }
+
+ mHandler = new QueryHandler(context);
+ mHandler.startQuery(TOKEN_QUERY_EVENT, null, mUri, EVENT_PROJECTION,
+ null, null, null);
+ }
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
@@ -1112,7 +1155,7 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
// Overwrites the one from Event table if available
if (!TextUtils.isEmpty(name)) {
mEventOrganizerDisplayName = name;
- if (!mIsOrganizer) {
+ if (!mIsOrganizer && view != null) {
setVisibilityCommon(view, R.id.organizer_container, View.VISIBLE);
setTextCommon(view, R.id.organizer, mEventOrganizerDisplayName);
}
@@ -1160,7 +1203,7 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
} while (mAttendeesCursor.moveToNext());
mAttendeesCursor.moveToFirst();
- updateAttendees(view);
+ if (view != null) updateAttendees(view);
}
}
}
@@ -1278,64 +1321,13 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
* Generates an .ics formatted file with the event info and launches intent chooser to
* share said file
*/
- private void shareEvent(ShareType type) {
- // Create the respective ICalendar objects from the event info
- VCalendar calendar = new VCalendar();
- calendar.addProperty(VCalendar.VERSION, "2.0");
- calendar.addProperty(VCalendar.PRODID, VCalendar.PRODUCT_IDENTIFIER);
- calendar.addProperty(VCalendar.CALSCALE, "GREGORIAN");
- calendar.addProperty(VCalendar.METHOD, "REQUEST");
-
- VEvent event = new VEvent();
- mEventCursor.moveToFirst();
- // add event start and end datetime
- if (!mAllDay) {
- String eventTimeZone = mEventCursor.getString(EVENT_INDEX_EVENT_TIMEZONE);
- event.addEventStart(mStartMillis, eventTimeZone);
- event.addEventEnd(mEndMillis, eventTimeZone);
- } else {
- // All-day events' start and end time are stored as UTC.
- // Treat the event start and end time as being in the local time zone and convert them
- // to the corresponding UTC datetime. If the UTC time is used as is, the ical recipients
- // will report the wrong start and end time (+/- 1 day) for the event as they will
- // convert the UTC time to their respective local time-zones
- String localTimeZone = Utils.getTimeZone(mActivity, mTZUpdater);
- long eventStart = IcalendarUtils.convertTimeToUtc(mStartMillis, localTimeZone);
- long eventEnd = IcalendarUtils.convertTimeToUtc(mEndMillis, localTimeZone);
- event.addEventStart(eventStart, "UTC");
- event.addEventEnd(eventEnd, "UTC");
- }
-
- event.addProperty(VEvent.LOCATION, mEventCursor.getString(EVENT_INDEX_EVENT_LOCATION));
- event.addProperty(VEvent.DESCRIPTION, mEventCursor.getString(EVENT_INDEX_DESCRIPTION));
- event.addProperty(VEvent.SUMMARY, mEventCursor.getString(EVENT_INDEX_TITLE));
- event.addOrganizer(new Organizer(mEventOrganizerDisplayName, mEventOrganizerEmail));
-
- // Add Attendees to event
- for (Attendee attendee : mAcceptedAttendees) {
- IcalendarUtils.addAttendeeToEvent(attendee, event);
- }
-
- for (Attendee attendee : mDeclinedAttendees) {
- IcalendarUtils.addAttendeeToEvent(attendee, event);
- }
-
- for (Attendee attendee : mTentativeAttendees) {
- IcalendarUtils.addAttendeeToEvent(attendee, event);
- }
-
- for (Attendee attendee : mNoResponseAttendees) {
- IcalendarUtils.addAttendeeToEvent(attendee, event);
- }
-
- // compose all of the ICalendar objects
- calendar.addEvent(event);
-
+ public void shareEvent(ShareType type) {
+ VCalendar calendar = generateVCalendar();
// create and share ics file
boolean isShareSuccessful = false;
try {
// event title serves as the file name prefix
- String filePrefix = event.getProperty(VEvent.SUMMARY);
+ String filePrefix = calendar.getFirstEvent().getProperty(VEvent.SUMMARY);
if (filePrefix == null || filePrefix.length() < 3) {
// default to a generic filename if event title doesn't qualify
// prefix length constraint is imposed by File#createTempFile
@@ -1358,8 +1350,7 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
dir = mActivity.getExternalCacheDir();
}
- File inviteFile = IcalendarUtils.createTempFile(filePrefix, ".ics",
- dir);
+ File inviteFile = IcalendarUtils.createTempFile(filePrefix, ".ics", dir);
if (IcalendarUtils.writeCalendarToFile(calendar, inviteFile)) {
if (type == ShareType.INTENT) {
@@ -1393,9 +1384,11 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
}
startActivity(chooserIntent);
} else {
- String msg = getString(R.string.cal_export_succ_msg);
- Toast.makeText(mActivity, String.format(msg, inviteFile),
- Toast.LENGTH_SHORT).show();
+ if (! mInNonUiMode) {
+ String msg = getString(R.string.cal_export_succ_msg);
+ Toast.makeText(mActivity, String.format(msg, inviteFile),
+ Toast.LENGTH_SHORT).show();
+ }
}
isShareSuccessful = true;
@@ -1414,6 +1407,66 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
}
}
+ /**
+ * Creates a calendar object (VCalendar) that adheres to the ICalendar specification
+ */
+ public VCalendar generateVCalendar() {
+
+ // Create the respective ICalendar objects from the event info
+ VCalendar calendar = new VCalendar();
+ calendar.addProperty(VCalendar.VERSION, "2.0");
+ calendar.addProperty(VCalendar.PRODID, VCalendar.PRODUCT_IDENTIFIER);
+ calendar.addProperty(VCalendar.CALSCALE, "GREGORIAN");
+ calendar.addProperty(VCalendar.METHOD, "REQUEST");
+
+ VEvent event = new VEvent();
+ mEventCursor.moveToFirst();
+ // add event start and end datetime
+ if (!mAllDay) {
+ String eventTimeZone = mEventCursor.getString(EVENT_INDEX_EVENT_TIMEZONE);
+ event.addEventStart(mStartMillis, eventTimeZone);
+ event.addEventEnd(mEndMillis, eventTimeZone);
+ } else {
+ // All-day events' start and end time are stored as UTC.
+ // Treat the event start and end time as being in the local time zone and convert them
+ // to the corresponding UTC datetime. If the UTC time is used as is, the ical recipients
+ // will report the wrong start and end time (+/- 1 day) for the event as they will
+ // convert the UTC time to their respective local time-zones
+ String localTimeZone = Utils.getTimeZone(mActivity, mTZUpdater);
+ long eventStart = IcalendarUtils.convertTimeToUtc(mStartMillis, localTimeZone);
+ long eventEnd = IcalendarUtils.convertTimeToUtc(mEndMillis, localTimeZone);
+ event.addEventStart(eventStart, "UTC");
+ event.addEventEnd(eventEnd, "UTC");
+ }
+
+ event.addProperty(VEvent.LOCATION, mEventCursor.getString(EVENT_INDEX_EVENT_LOCATION));
+ event.addProperty(VEvent.DESCRIPTION, mEventCursor.getString(EVENT_INDEX_DESCRIPTION));
+ event.addProperty(VEvent.SUMMARY, mEventCursor.getString(EVENT_INDEX_TITLE));
+ event.addOrganizer(new Organizer(mEventOrganizerDisplayName, mEventOrganizerEmail));
+
+ // Add Attendees to event
+ for (Attendee attendee : mAcceptedAttendees) {
+ IcalendarUtils.addAttendeeToEvent(attendee, event);
+ }
+
+ for (Attendee attendee : mDeclinedAttendees) {
+ IcalendarUtils.addAttendeeToEvent(attendee, event);
+ }
+
+ for (Attendee attendee : mTentativeAttendees) {
+ IcalendarUtils.addAttendeeToEvent(attendee, event);
+ }
+
+ for (Attendee attendee : mNoResponseAttendees) {
+ IcalendarUtils.addAttendeeToEvent(attendee, event);
+ }
+
+ // compose all of the ICalendar objects
+ calendar.addEvent(event);
+
+ return calendar;
+ }
+
private void showEventColorPickerDialog() {
if (mColorPickerDialog == null) {
mColorPickerDialog = EventColorPickerDialog.newInstance(mColors, mCurrentColor,
@@ -1925,12 +1978,15 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
mEventOrganizerDisplayName = mEventOrganizerEmail;
}
- if (!mIsOrganizer && !TextUtils.isEmpty(mEventOrganizerDisplayName)) {
- setTextCommon(view, R.id.organizer, mEventOrganizerDisplayName);
- setVisibilityCommon(view, R.id.organizer_container, View.VISIBLE);
- } else {
- setVisibilityCommon(view, R.id.organizer_container, View.GONE);
+ if (!mInNonUiMode) {
+ if (!mIsOrganizer && !TextUtils.isEmpty(mEventOrganizerDisplayName)) {
+ setTextCommon(view, R.id.organizer, mEventOrganizerDisplayName);
+ setVisibilityCommon(view, R.id.organizer_container, View.VISIBLE);
+ } else {
+ setVisibilityCommon(view, R.id.organizer_container, View.GONE);
+ }
}
+
mHasAttendeeData = mEventCursor.getInt(EVENT_INDEX_HAS_ATTENDEE_DATA) != 0;
mCanModifyCalendar = mEventCursor.getInt(EVENT_INDEX_ACCESS_LEVEL)
>= Calendars.CAL_ACCESS_CONTRIBUTOR;
@@ -1939,6 +1995,9 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
mIsBusyFreeCalendar =
mEventCursor.getInt(EVENT_INDEX_ACCESS_LEVEL) == Calendars.CAL_ACCESS_FREEBUSY;
+ // no more work to be done if launched in non-ui mode
+ if (mInNonUiMode) return;
+
if (!mIsBusyFreeCalendar) {
View b = mView.findViewById(R.id.edit);
@@ -1978,8 +2037,8 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
mActivity.invalidateOptionsMenu();
}
} else {
- setVisibilityCommon(view, R.id.calendar, View.GONE);
- sendAccessibilityEventIfQueryDone(TOKEN_QUERY_DUPLICATE_CALENDARS);
+ if (!mInNonUiMode) setVisibilityCommon(view, R.id.calendar, View.GONE);
+ assessQueryCompletion(TOKEN_QUERY_DUPLICATE_CALENDARS);
}
}
diff --git a/src/com/android/calendar/ShareCalendarActivity.java b/src/com/android/calendar/ShareCalendarActivity.java
new file mode 100644
index 00000000..cd538ca6
--- /dev/null
+++ b/src/com/android/calendar/ShareCalendarActivity.java
@@ -0,0 +1,229 @@
+package com.android.calendar;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.CalendarContract;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import com.android.calendar.agenda.AgendaFragment;
+import com.android.calendar.icalendar.IcalendarUtils;
+import com.android.calendar.icalendar.VCalendar;
+import com.android.calendar.icalendar.VEvent;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+
+/**
+ * Handles requests for sharing calendar events
+ * This activity returns a vcs formatted file
+ */
+public class ShareCalendarActivity extends Activity implements CalendarUtils.ShareEventListener {
+
+ public static final String EXTRA_LIMIT_TO_ONE_EVENT = "EXTRA_LIMIT_TO_ONE_EVENT";
+
+ private static final String TAG = "ShareCalendarActivity";
+
+ private HashSet<CalendarUtils.Triple<Long, Long, Long>> mShareEventsList =
+ new HashSet<CalendarUtils.Triple<Long, Long, Long>>();
+
+ private ArrayList<EventInfoFragment> mEventDataFragments = new ArrayList<EventInfoFragment>();
+
+ private ActionBar mActionBar;
+ private AgendaFragment mAgendaFragment;
+ private long mStartMillis;
+ private ArrayList<Uri> mFileUris = new ArrayList<Uri>();
+ private int mNumQueriesCompleted;
+ private boolean mShouldSelectSingleEvent;
+ private Resources mResources;
+ private String mNoSelectionMsg;
+
+ @Override
+ public void onEventShared(CalendarUtils.Triple<Long, Long, Long> eventInfo) {
+ if (eventInfo.first < 0) return;
+
+ mShareEventsList.add(eventInfo);
+ updateSubtitle();
+ }
+
+ @Override
+ public void onEventRemoval(long eventId) {
+ if (eventId < 0) return;
+
+ CalendarUtils.Triple<Long, Long, Long> eventInfo =
+ new CalendarUtils.Triple<Long, Long, Long>(eventId, 0l, 0l);
+ mShareEventsList.remove(eventInfo);
+ updateSubtitle();
+ }
+
+ @Override
+ public void onResetShareList() {
+ // undo
+ mShareEventsList.clear();
+ updateSubtitle();
+ }
+
+ public void updateSubtitle() {
+ int listSize = mShareEventsList.size();
+ String subtitle;
+ // workaround for Android's poor pluralization treatment of 'zero' quantity in English
+ if (listSize == 0) {
+ subtitle = mNoSelectionMsg;
+ } else {
+ subtitle = mResources.getQuantityString(R.plurals.events_selected,
+ listSize, listSize);
+ }
+ mActionBar.setSubtitle(subtitle);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Intent intent = getIntent();
+ Bundle args = intent.getExtras();
+ if (args != null) {
+ mShouldSelectSingleEvent = args.getBoolean(EXTRA_LIMIT_TO_ONE_EVENT, false);
+ }
+
+ mStartMillis = System.currentTimeMillis();
+ setContentView(R.layout.simple_frame_layout);
+ mResources = getResources();
+
+ // create agenda fragment displaying the list of calendar events
+ FragmentManager fragmentManager = getFragmentManager();
+ FragmentTransaction ft = fragmentManager.beginTransaction();
+ mAgendaFragment = new AgendaFragment(mStartMillis, false, true);
+ mAgendaFragment.setShareModeOptions(this, mShouldSelectSingleEvent);
+ ft.replace(R.id.main_frame, mAgendaFragment);
+ ft.commit();
+
+ mActionBar = getActionBar();
+ mActionBar.setDisplayShowTitleEnabled(true);
+ String title = mShouldSelectSingleEvent ?
+ mResources.getQuantityString(R.plurals.select_events_to_share, 1) :
+ mResources.getQuantityString(R.plurals.select_events_to_share, 2) ;
+
+ mActionBar.setTitle(title);
+ mNoSelectionMsg = mResources.getString(R.string.no_events_selected);
+ updateSubtitle();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.share_event_title_bar, menu);
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+
+ case(R.id.action_done):
+ generateEventData();
+ evalIfComplete();
+ break;
+
+ case (R.id.action_cancel):
+ setResultAndFinish(false);
+ break;
+
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ // called after the data fragment's is done loading
+ public void queryComplete() {
+ mNumQueriesCompleted++;
+ evalIfComplete();
+ }
+
+ // used load event information for the list of selected events
+ private void generateEventData() {
+ for (CalendarUtils.Triple<Long, Long, Long> event : mShareEventsList) {
+
+ long eventId = event.first;
+ long eventStartMillis = event.second;
+ long eventEndMillis = event.third;
+
+ // EventInfoFragment just serves as a data fragment and is initialized with
+ // default arguments for parameters that don't affect model loading
+ EventInfoFragment eif = new EventInfoFragment(this, eventId, eventStartMillis,
+ eventEndMillis, CalendarContract.Attendees.ATTENDEE_STATUS_NONE, false, 0,
+ null);
+ eif.launchInNonUiMode();
+ eif.startQueryingData(this);
+ eif.setQueryCompleteRunnable(new Runnable() {
+ @Override
+ public void run() {
+ // indicate model loading is complete
+ queryComplete();
+ }
+ });
+
+ mEventDataFragments.add(eif);
+ }
+
+ }
+
+ // generates the vcs files if the data for selected events has been successfully queried
+ private void evalIfComplete() {
+ if (mNumQueriesCompleted != 0 && mNumQueriesCompleted == mEventDataFragments.size()) {
+
+ for(EventInfoFragment event : mEventDataFragments) {
+ try {
+ // generate vcs file
+ VCalendar calendar = event.generateVCalendar();
+ // event title serves as the file name prefix
+ String filePrefix = calendar.getFirstEvent().getProperty(VEvent.SUMMARY);
+ if (filePrefix == null || filePrefix.length() < 3) {
+ // default to a generic filename if event title doesn't qualify
+ // prefix length constraint is imposed by File#createTempFile
+ filePrefix = "invite";
+ }
+
+ filePrefix = filePrefix.replaceAll("\\W+", " ");
+
+ if (!filePrefix.endsWith(" ")) {
+ filePrefix += " ";
+ }
+ File dir = getExternalCacheDir();
+ File inviteFile = IcalendarUtils.createTempFile(filePrefix, ".vcs", dir);
+ inviteFile.setReadable(true, false); // set world-readable
+ if (IcalendarUtils.writeCalendarToFile(calendar, inviteFile)) {
+ mFileUris.add(Uri.fromFile(inviteFile));
+ }
+ } catch (IOException ioe) {
+ break;
+ }
+ }
+
+ setResultAndFinish(true);
+
+ } else if (mEventDataFragments.size() < 1) { // if no events have been selected
+ setResultAndFinish(false);
+ }
+ }
+
+ private void setResultAndFinish(boolean isResultAvailable) {
+ if (isResultAvailable) {
+ Intent intent = new Intent();
+ intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, mFileUris);
+ setResult(RESULT_OK, intent);
+ finish();
+ } else {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ }
+}
diff --git a/src/com/android/calendar/agenda/AgendaAdapter.java b/src/com/android/calendar/agenda/AgendaAdapter.java
index 9e492832..0b42bb9d 100644
--- a/src/com/android/calendar/agenda/AgendaAdapter.java
+++ b/src/com/android/calendar/agenda/AgendaAdapter.java
@@ -26,6 +26,7 @@ import android.text.format.DateUtils;
import android.text.format.Time;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.CheckBox;
import android.widget.LinearLayout;
import android.widget.ResourceCursorAdapter;
import android.widget.TextView;
@@ -78,6 +79,7 @@ public class AgendaAdapter extends ResourceCursorAdapter {
boolean allDay;
boolean grayed;
int julianDay;
+ CheckBox selectedForSharing;
}
public AgendaAdapter(Context context, int resource) {
@@ -125,6 +127,7 @@ public class AgendaAdapter extends ResourceCursorAdapter {
view.findViewById(R.id.agenda_item_text_container);
holder.selectedMarker = view.findViewById(R.id.selected_marker);
holder.colorChip = (ColorChipView)view.findViewById(R.id.agenda_item_color);
+ holder.selectedForSharing = (CheckBox) view.findViewById(R.id.shareCheckbox);
}
holder.startTimeMilli = cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
diff --git a/src/com/android/calendar/agenda/AgendaFragment.java b/src/com/android/calendar/agenda/AgendaFragment.java
index ff5c47cc..6328bd63 100644
--- a/src/com/android/calendar/agenda/AgendaFragment.java
+++ b/src/com/android/calendar/agenda/AgendaFragment.java
@@ -41,6 +41,7 @@ import com.android.calendar.CalendarController.ViewType;
import com.android.calendar.EventInfoFragment;
import com.android.calendar.GeneralPreferences;
import com.android.calendar.R;
+import com.android.calendar.CalendarUtils.ShareEventListener;
import com.android.calendar.StickyHeaderListView;
import com.android.calendar.Utils;
@@ -71,8 +72,9 @@ public class AgendaFragment extends Fragment implements CalendarController.Event
private AgendaWindowAdapter mAdapter = null;
private boolean mForceReplace = true;
private long mLastShownEventId = -1;
-
-
+ private boolean mLaunchedInShareMode;
+ private boolean mShouldSelectSingleEvent;
+ private ShareEventListener mShareEventListener;
// Tracks the time of the top visible view in order to send UPDATE_TITLE messages to the action
// bar.
@@ -87,13 +89,17 @@ public class AgendaFragment extends Fragment implements CalendarController.Event
};
public AgendaFragment() {
- this(0, false);
+ this(0, false, false);
}
+ public AgendaFragment(long timeMillis, boolean usedForSearch) {
+ this(0, usedForSearch, false);
+ }
// timeMillis - time of first event to show
// usedForSearch - indicates if this fragment is used in the search fragment
- public AgendaFragment(long timeMillis, boolean usedForSearch) {
+ // inShareMode - indicates whether the fragment was started to share calendar events
+ public AgendaFragment(long timeMillis, boolean usedForSearch, boolean inShareMode) {
mInitialTimeMillis = timeMillis;
mTime = new Time();
mLastHandledEventTime = new Time();
@@ -105,6 +111,7 @@ public class AgendaFragment extends Fragment implements CalendarController.Event
}
mLastHandledEventTime.set(mTime);
mUsedForSearch = usedForSearch;
+ mLaunchedInShareMode = inShareMode;
}
@Override
@@ -142,7 +149,6 @@ public class AgendaFragment extends Fragment implements CalendarController.Event
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
-
int screenWidth = mActivity.getResources().getDisplayMetrics().widthPixels;
View v = inflater.inflate(R.layout.agenda_fragment, null);
@@ -168,14 +174,24 @@ public class AgendaFragment extends Fragment implements CalendarController.Event
if (lv != null) {
Adapter a = mAgendaListView.getAdapter();
lv.setAdapter(a);
+
if (a instanceof HeaderViewListAdapter) {
mAdapter = (AgendaWindowAdapter) ((HeaderViewListAdapter)a).getWrappedAdapter();
+ if (mLaunchedInShareMode) {
+ mAdapter.launchInShareMode(true, mShouldSelectSingleEvent);
+ mAgendaListView.launchInShareMode(true, mShouldSelectSingleEvent);
+ if (mShareEventListener != null) {
+ mAgendaListView.setShareEventListener(mShareEventListener);
+ }
+ }
lv.setIndexer(mAdapter);
lv.setHeaderHeightListener(mAdapter);
+
} else if (a instanceof AgendaWindowAdapter) {
mAdapter = (AgendaWindowAdapter)a;
lv.setIndexer(mAdapter);
lv.setHeaderHeightListener(mAdapter);
+
} else {
Log.wtf(TAG, "Cannot find HeaderIndexer for StickyHeaderListView");
}
@@ -208,6 +224,13 @@ public class AgendaFragment extends Fragment implements CalendarController.Event
return v;
}
+ // configure share mode launch options
+ public void setShareModeOptions(ShareEventListener listener, boolean selectSingleEvent) {
+ mShareEventListener = listener;
+ mShouldSelectSingleEvent = selectSingleEvent;
+
+ }
+
@Override
public void onResume() {
super.onResume();
diff --git a/src/com/android/calendar/agenda/AgendaListView.java b/src/com/android/calendar/agenda/AgendaListView.java
index 6cfc7e5b..f3270e66 100644
--- a/src/com/android/calendar/agenda/AgendaListView.java
+++ b/src/com/android/calendar/agenda/AgendaListView.java
@@ -20,6 +20,8 @@ import com.android.calendar.CalendarController;
import com.android.calendar.CalendarController.EventType;
import com.android.calendar.DeleteEventHelper;
import com.android.calendar.R;
+import com.android.calendar.CalendarUtils.ShareEventListener;
+import com.android.calendar.CalendarUtils.Triple;
import com.android.calendar.Utils;
import com.android.calendar.agenda.AgendaAdapter.ViewHolder;
import com.android.calendar.agenda.AgendaWindowAdapter.DayAdapterInfo;
@@ -51,6 +53,9 @@ public class AgendaListView extends ListView implements OnItemClickListener {
private Time mTime;
private boolean mShowEventDetailsWithAgenda;
private Handler mHandler = null;
+ private boolean mLaunchedInShareMode;
+ private boolean mShouldSelectSingleEvent;
+ private ShareEventListener mShareEventListener;
private final Runnable mTZUpdater = new Runnable() {
@Override
@@ -86,6 +91,12 @@ public class AgendaListView extends ListView implements OnItemClickListener {
initView(context);
}
+ // "share mode" is off by default
+ public void launchInShareMode(boolean inShareMode, boolean selectSingleEvent) {
+ mLaunchedInShareMode = true;
+ mShouldSelectSingleEvent = selectSingleEvent;
+ }
+
private void initView(Context context) {
mContext = context;
mTimeZone = Utils.getTimeZone(context, mTZUpdater);
@@ -108,6 +119,10 @@ public class AgendaListView extends ListView implements OnItemClickListener {
mHandler = new Handler();
}
+ public void setShareEventListener(ShareEventListener listener) {
+ mShareEventListener = listener;
+ }
+
// Sets a thread to run every EVENT_UPDATE_TIME in order to update the list
// with grayed out past events
private void setPastEventsUpdater() {
@@ -197,10 +212,30 @@ public class AgendaListView extends ListView implements OnItemClickListener {
endTime = Utils.convertAlldayLocalToUTC(mTime, endTime, mTimeZone);
}
mTime.set(startTime);
- CalendarController controller = CalendarController.getInstance(mContext);
- controller.sendEventRelatedEventWithExtra(this, EventType.VIEW_EVENT, item.id,
- startTime, endTime, 0, 0, CalendarController.EventInfo.buildViewExtraLong(
- Attendees.ATTENDEE_STATUS_NONE, item.allDay), holderStartTime);
+
+ // divert click action to either a ShareEventListener or the Controller
+ if (mShareEventListener != null && mLaunchedInShareMode) {
+ long viewId = ((ViewHolder) holder).instanceId;
+
+ if (mWindowAdapter.isEventInShareList(viewId)) {
+ Triple<Long, Long, Long> eventinfo =
+ new Triple<Long, Long, Long>(item.id, item.begin, item.end);
+ if (mShouldSelectSingleEvent) mShareEventListener.onResetShareList();
+ mShareEventListener.onEventShared(eventinfo);
+
+ } else {
+ // submit event removal
+ mShareEventListener.onEventRemoval(item.id);
+ }
+
+ } else {
+ CalendarController controller = CalendarController.getInstance(mContext);
+ controller.sendEventRelatedEventWithExtra(this, EventType.VIEW_EVENT, item.id,
+ startTime, endTime, 0, 0,
+ CalendarController.EventInfo.buildViewExtraLong(
+ Attendees.ATTENDEE_STATUS_NONE, item.allDay),
+ holderStartTime);
+ }
}
}
}
diff --git a/src/com/android/calendar/agenda/AgendaWindowAdapter.java b/src/com/android/calendar/agenda/AgendaWindowAdapter.java
index 9fd59f0f..97822f98 100644
--- a/src/com/android/calendar/agenda/AgendaWindowAdapter.java
+++ b/src/com/android/calendar/agenda/AgendaWindowAdapter.java
@@ -50,6 +50,7 @@ import com.android.calendar.Utils;
import java.util.Date;
import java.util.Formatter;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Locale;
@@ -74,7 +75,7 @@ Check for leaks and excessive allocations
*/
public class AgendaWindowAdapter extends BaseAdapter
- implements StickyHeaderListView.HeaderIndexer, StickyHeaderListView.HeaderHeightListener{
+ implements StickyHeaderListView.HeaderIndexer, StickyHeaderListView.HeaderHeightListener {
static final boolean BASICLOG = false;
static final boolean DEBUGLOG = false;
@@ -228,6 +229,10 @@ public class AgendaWindowAdapter extends BaseAdapter
private final int mSelectedItemTextColor;
private final float mItemRightMargin;
+ private boolean mLaunchedInShareMode;
+ private boolean mShouldSelectSingleEvent;
+ private HashSet<Long> mSharedEvents = new HashSet<Long>();
+
// Types of Query
private static final int QUERY_TYPE_OLDER = 0; // Query for older events
private static final int QUERY_TYPE_NEWER = 1; // Query for newer events
@@ -369,6 +374,12 @@ public class AgendaWindowAdapter extends BaseAdapter
mAgendaListView.addHeaderView(mHeaderView);
}
+ // "share mode" is off by default
+ public void launchInShareMode(boolean inShareMode, boolean selectSingleEvent) {
+ mLaunchedInShareMode = inShareMode;
+ mShouldSelectSingleEvent = selectSingleEvent;
+ }
+
// Method in Adapter
@Override
public int getViewTypeCount() {
@@ -485,6 +496,25 @@ public class AgendaWindowAdapter extends BaseAdapter
pastPresentDivider.setVisibility(View.GONE);
}
}
+
+ if (mLaunchedInShareMode) {
+ Object tag = v.getTag();
+ if (tag instanceof AgendaAdapter.ViewHolder) {
+ AgendaAdapter.ViewHolder vh = (AgendaAdapter.ViewHolder) tag;
+
+ // toggle visibility of share checkbox
+ vh.selectedForSharing.setVisibility(View.VISIBLE);
+ vh.selectedForSharing.setClickable(false);
+
+ // set 'checked' status
+ if (mSharedEvents.contains(vh.instanceId)) {
+ vh.selectedForSharing.setChecked(true);
+ } else {
+ vh.selectedForSharing.setChecked(false);
+ }
+ }
+ }
+
} else {
// TODO
Log.e(TAG, "BUG: getAdapterInfoByPosition returned null!!! " + position);
@@ -1310,10 +1340,32 @@ public class AgendaWindowAdapter extends BaseAdapter
Object vh = v.getTag();
if (vh instanceof AgendaAdapter.ViewHolder) {
mSelectedVH = (AgendaAdapter.ViewHolder) vh;
+ boolean datasetChanged = false;
+
+ if (mLaunchedInShareMode) {
+
+ if (mShouldSelectSingleEvent) {
+ mSharedEvents.clear();
+ mSharedEvents.add(mSelectedVH.instanceId);
+ } else {
+
+ if (mSharedEvents.contains(mSelectedVH.instanceId)) {
+ mSharedEvents.remove(mSelectedVH.instanceId);
+ } else {
+ mSharedEvents.add(mSelectedVH.instanceId);
+ }
+
+ }
+
+ datasetChanged = true;
+ }
+
if (mSelectedInstanceId != mSelectedVH.instanceId) {
mSelectedInstanceId = mSelectedVH.instanceId;
- notifyDataSetChanged();
+ datasetChanged = true;
}
+
+ if (datasetChanged) notifyDataSetChanged();
}
}
}
@@ -1397,6 +1449,10 @@ public class AgendaWindowAdapter extends BaseAdapter
return -1;
}
+ public boolean isEventInShareList(long id) {
+ return mSharedEvents.contains(id);
+ }
+
@Override
public void OnHeaderHeightChanged(int height) {
mStickyHeaderSize = height;
diff --git a/src/com/android/calendar/icalendar/VCalendar.java b/src/com/android/calendar/icalendar/VCalendar.java
index 9f422e6f..140d9358 100644
--- a/src/com/android/calendar/icalendar/VCalendar.java
+++ b/src/com/android/calendar/icalendar/VCalendar.java
@@ -52,11 +52,11 @@ public class VCalendar {
* Add specified property
* @param property
* @param value
- * @return
*/
public boolean addProperty(String property, String value) {
- // since all the required mProperties are unary (only one can exist) , taking a shortcut here
- // when multiples of a property can exist , enforce that here .. cleverly
+ // since all the required mProperties are unary (only one can exist) , taking a shortcut
+ // here
+ // TODO: when multiple attributes of a property can exist , enforce that here
if (sPropertyList.containsKey(property) && value != null) {
mProperties.put(property, IcalendarUtils.cleanseString(value));
return true;
@@ -73,16 +73,25 @@ public class VCalendar {
}
/**
- *
- * @return
+ * Returns all the events that are part of this calendar
*/
public LinkedList<VEvent> getAllEvents() {
return mEvents;
}
/**
+ * Returns the first event of the calendar
+ */
+ public VEvent getFirstEvent() {
+ if (mEvents != null && mEvents.size() > 0) {
+ return mEvents.get(0);
+ } else {
+ return null;
+ }
+ }
+
+ /**
* Returns the iCal representation of the calendar and all of its inherent components
- * @return
*/
public String getICalFormattedString() {
StringBuilder output = new StringBuilder();