am 92a90a31: (-s ours) Import revised translations.  DO NOT MERGE

Merge commit '92a90a31c8842b89793771784719c52950c9237e' into eclair

* commit '92a90a31c8842b89793771784719c52950c9237e':
  Import revised translations.  DO NOT MERGE
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 80bb31d..064f8ae 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -24,9 +24,11 @@
 
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.VIBRATE"/>
+    <uses-permission android:name="android.permission.READ_CONTACTS"/>
     <uses-permission android:name="android.permission.READ_CALENDAR" />
     <uses-permission android:name="android.permission.WRITE_CALENDAR" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
     <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.mail" />
 
     <application android:name="CalendarApplication"
@@ -37,8 +39,7 @@
         <uses-library android:name="android.test.runner" />
 
         <activity android:name="LaunchActivity"
-            android:theme="@android:style/Theme.Light"
-            android:clearTaskOnLaunch="true">
+            android:theme="@android:style/Theme.NoDisplay">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -57,7 +58,7 @@
             android:exported="true" />
         
         <activity android:name="EditEvent" android:label="@string/event_edit_title"
-            android:theme="@android:style/Theme.Light"
+            android:theme="@android:style/Theme"
             android:configChanges="orientation|keyboardHidden">
             
             <intent-filter>
@@ -77,6 +78,22 @@
                 <data android:mimeType="vnd.android.cursor.item/event" />
             </intent-filter>
         </activity>
+
+        <activity android:name="GoogleCalendarUriIntentFilter" android:label="@string/app_label"
+            android:theme="@android:style/Theme.Light"
+            android:configChanges="orientation|keyboardHidden">
+
+            <intent-filter>
+               <action android:name="android.intent.action.VIEW" />
+               <category android:name="android.intent.category.DEFAULT" />
+               <category android:name="android.intent.category.BROWSABLE" />
+               <data android:scheme="http" android:host="www.google.com" android:pathPrefix="/calendar/event" />
+               <data android:scheme="https" android:host="www.google.com" android:pathPrefix="/calendar/event" />
+               <data android:scheme="http" android:host="www.google.com" android:pathPattern="/calendar/hosted/.*/event" />
+               <data android:scheme="https" android:host="www.google.com" android:pathPattern="/calendar/hosted/.*/event" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="SelectCalendarsActivity" android:label="@string/calendars_title" />
         <activity android:name="CalendarPreferenceActivity" android:label="@string/preferences_title" />
         <activity android:name="AlertActivity" android:launchMode="singleInstance"
diff --git a/res/drawable-hdpi-finger/btn_circle_disable.png b/res/drawable-hdpi-finger/btn_circle_disable.png
new file mode 100644
index 0000000..4f12078
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_circle_disable.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_circle_disable_focused.png b/res/drawable-hdpi-finger/btn_circle_disable_focused.png
new file mode 100644
index 0000000..bc0d77b
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_circle_disable_focused.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_circle_normal.png b/res/drawable-hdpi-finger/btn_circle_normal.png
new file mode 100644
index 0000000..d1e21d9
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_circle_normal.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_circle_pressed.png b/res/drawable-hdpi-finger/btn_circle_pressed.png
new file mode 100644
index 0000000..31e69e2
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_circle_pressed.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_circle_selected.png b/res/drawable-hdpi-finger/btn_circle_selected.png
new file mode 100644
index 0000000..0f809ee
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_circle_selected.png
Binary files differ
diff --git a/res/drawable-hdpi/app_icon.png b/res/drawable-hdpi/app_icon.png
new file mode 100644
index 0000000..d4cafaa
--- /dev/null
+++ b/res/drawable-hdpi/app_icon.png
Binary files differ
diff --git a/res/drawable-hdpi/bg_cal_card.9.png b/res/drawable-hdpi/bg_cal_card.9.png
new file mode 100644
index 0000000..bd76409
--- /dev/null
+++ b/res/drawable-hdpi/bg_cal_card.9.png
Binary files differ
diff --git a/res/drawable-hdpi/box_appointment_normal.9.png b/res/drawable-hdpi/box_appointment_normal.9.png
new file mode 100644
index 0000000..84d528c
--- /dev/null
+++ b/res/drawable-hdpi/box_appointment_normal.9.png
Binary files differ
diff --git a/res/drawable-hdpi/box_appointment_pressed.9.png b/res/drawable-hdpi/box_appointment_pressed.9.png
new file mode 100644
index 0000000..3dae23d
--- /dev/null
+++ b/res/drawable-hdpi/box_appointment_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi/box_appointment_selected.9.png b/res/drawable-hdpi/box_appointment_selected.9.png
new file mode 100644
index 0000000..55eb437
--- /dev/null
+++ b/res/drawable-hdpi/box_appointment_selected.9.png
Binary files differ
diff --git a/res/drawable-hdpi/dna_1_of_6.png b/res/drawable-hdpi/dna_1_of_6.png
new file mode 100644
index 0000000..bcefba7
--- /dev/null
+++ b/res/drawable-hdpi/dna_1_of_6.png
Binary files differ
diff --git a/res/drawable-hdpi/dna_2345_of_6.png b/res/drawable-hdpi/dna_2345_of_6.png
new file mode 100644
index 0000000..0a2f1a8
--- /dev/null
+++ b/res/drawable-hdpi/dna_2345_of_6.png
Binary files differ
diff --git a/res/drawable-hdpi/dna_6_of_6.png b/res/drawable-hdpi/dna_6_of_6.png
new file mode 100644
index 0000000..c9d216e
--- /dev/null
+++ b/res/drawable-hdpi/dna_6_of_6.png
Binary files differ
diff --git a/res/drawable-hdpi/dna_empty.png b/res/drawable-hdpi/dna_empty.png
new file mode 100644
index 0000000..3b5e335
--- /dev/null
+++ b/res/drawable-hdpi/dna_empty.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_alarm_dark.png b/res/drawable-hdpi/ic_alarm_dark.png
new file mode 100644
index 0000000..272c489
--- /dev/null
+++ b/res/drawable-hdpi/ic_alarm_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_alarm_white.png b/res/drawable-hdpi/ic_alarm_white.png
new file mode 100644
index 0000000..7602182
--- /dev/null
+++ b/res/drawable-hdpi/ic_alarm_white.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_btn_round_minus.png b/res/drawable-hdpi/ic_btn_round_minus.png
new file mode 100644
index 0000000..02bec7d
--- /dev/null
+++ b/res/drawable-hdpi/ic_btn_round_minus.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_btn_round_plus.png b/res/drawable-hdpi/ic_btn_round_plus.png
new file mode 100644
index 0000000..1fdfb69
--- /dev/null
+++ b/res/drawable-hdpi/ic_btn_round_plus.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_contact_picture.png b/res/drawable-hdpi/ic_contact_picture.png
new file mode 100755
index 0000000..7c34f5c
--- /dev/null
+++ b/res/drawable-hdpi/ic_contact_picture.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_reminder.png b/res/drawable-hdpi/ic_menu_reminder.png
new file mode 100644
index 0000000..64cf5f0
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_reminder.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_show_list.png b/res/drawable-hdpi/ic_menu_show_list.png
new file mode 100644
index 0000000..047cc12
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_show_list.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_repeat_dark.png b/res/drawable-hdpi/ic_repeat_dark.png
new file mode 100644
index 0000000..8402fa2
--- /dev/null
+++ b/res/drawable-hdpi/ic_repeat_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_repeat_white.png b/res/drawable-hdpi/ic_repeat_white.png
new file mode 100644
index 0000000..9a595fb
--- /dev/null
+++ b/res/drawable-hdpi/ic_repeat_white.png
Binary files differ
diff --git a/res/drawable-hdpi/im_avatar_picture_border_normal.9.png b/res/drawable-hdpi/im_avatar_picture_border_normal.9.png
new file mode 100755
index 0000000..2367f98
--- /dev/null
+++ b/res/drawable-hdpi/im_avatar_picture_border_normal.9.png
Binary files differ
diff --git a/res/drawable-hdpi/month_view_background.9.png b/res/drawable-hdpi/month_view_background.9.png
new file mode 100644
index 0000000..1108a78
--- /dev/null
+++ b/res/drawable-hdpi/month_view_background.9.png
Binary files differ
diff --git a/res/drawable-hdpi/month_view_longpress.9.png b/res/drawable-hdpi/month_view_longpress.9.png
new file mode 100644
index 0000000..aa8179d
--- /dev/null
+++ b/res/drawable-hdpi/month_view_longpress.9.png
Binary files differ
diff --git a/res/drawable-hdpi/month_view_pressed.9.png b/res/drawable-hdpi/month_view_pressed.9.png
new file mode 100644
index 0000000..0868dfd
--- /dev/null
+++ b/res/drawable-hdpi/month_view_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi/month_view_selected.9.png b/res/drawable-hdpi/month_view_selected.9.png
new file mode 100644
index 0000000..e3236ad
--- /dev/null
+++ b/res/drawable-hdpi/month_view_selected.9.png
Binary files differ
diff --git a/res/drawable-hdpi/month_view_today_background.9.png b/res/drawable-hdpi/month_view_today_background.9.png
new file mode 100644
index 0000000..fbf1553
--- /dev/null
+++ b/res/drawable-hdpi/month_view_today_background.9.png
Binary files differ
diff --git a/res/drawable-hdpi/stat_notify_calendar.png b/res/drawable-hdpi/stat_notify_calendar.png
new file mode 100644
index 0000000..7e7cd60
--- /dev/null
+++ b/res/drawable-hdpi/stat_notify_calendar.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_calendar_event.png b/res/drawable-hdpi/sym_calendar_event.png
new file mode 100644
index 0000000..3faeb88
--- /dev/null
+++ b/res/drawable-hdpi/sym_calendar_event.png
Binary files differ
diff --git a/res/drawable-land-hdpi/dna_1_of_6.png b/res/drawable-land-hdpi/dna_1_of_6.png
new file mode 100644
index 0000000..82747df
--- /dev/null
+++ b/res/drawable-land-hdpi/dna_1_of_6.png
Binary files differ
diff --git a/res/drawable-land-hdpi/dna_2345_of_6.png b/res/drawable-land-hdpi/dna_2345_of_6.png
new file mode 100644
index 0000000..cd68492
--- /dev/null
+++ b/res/drawable-land-hdpi/dna_2345_of_6.png
Binary files differ
diff --git a/res/drawable-land-hdpi/dna_6_of_6.png b/res/drawable-land-hdpi/dna_6_of_6.png
new file mode 100644
index 0000000..2c082a0
--- /dev/null
+++ b/res/drawable-land-hdpi/dna_6_of_6.png
Binary files differ
diff --git a/res/drawable-land-hdpi/dna_empty.png b/res/drawable-land-hdpi/dna_empty.png
new file mode 100644
index 0000000..26a8518
--- /dev/null
+++ b/res/drawable-land-hdpi/dna_empty.png
Binary files differ
diff --git a/res/drawable-land/dna_1_of_6.png b/res/drawable-land-mdpi/dna_1_of_6.png
similarity index 100%
rename from res/drawable-land/dna_1_of_6.png
rename to res/drawable-land-mdpi/dna_1_of_6.png
Binary files differ
diff --git a/res/drawable-land/dna_2345_of_6.png b/res/drawable-land-mdpi/dna_2345_of_6.png
similarity index 100%
rename from res/drawable-land/dna_2345_of_6.png
rename to res/drawable-land-mdpi/dna_2345_of_6.png
Binary files differ
diff --git a/res/drawable-land/dna_6_of_6.png b/res/drawable-land-mdpi/dna_6_of_6.png
similarity index 100%
rename from res/drawable-land/dna_6_of_6.png
rename to res/drawable-land-mdpi/dna_6_of_6.png
Binary files differ
diff --git a/res/drawable-land/dna_empty.png b/res/drawable-land-mdpi/dna_empty.png
similarity index 100%
rename from res/drawable-land/dna_empty.png
rename to res/drawable-land-mdpi/dna_empty.png
Binary files differ
diff --git a/res/drawable-finger/btn_circle_disable.png b/res/drawable-mdpi-finger/btn_circle_disable.png
similarity index 100%
rename from res/drawable-finger/btn_circle_disable.png
rename to res/drawable-mdpi-finger/btn_circle_disable.png
Binary files differ
diff --git a/res/drawable-finger/btn_circle_disable_focused.png b/res/drawable-mdpi-finger/btn_circle_disable_focused.png
similarity index 100%
rename from res/drawable-finger/btn_circle_disable_focused.png
rename to res/drawable-mdpi-finger/btn_circle_disable_focused.png
Binary files differ
diff --git a/res/drawable-finger/btn_circle_normal.png b/res/drawable-mdpi-finger/btn_circle_normal.png
similarity index 100%
rename from res/drawable-finger/btn_circle_normal.png
rename to res/drawable-mdpi-finger/btn_circle_normal.png
Binary files differ
diff --git a/res/drawable-finger/btn_circle_pressed.png b/res/drawable-mdpi-finger/btn_circle_pressed.png
similarity index 100%
rename from res/drawable-finger/btn_circle_pressed.png
rename to res/drawable-mdpi-finger/btn_circle_pressed.png
Binary files differ
diff --git a/res/drawable-finger/btn_circle_selected.png b/res/drawable-mdpi-finger/btn_circle_selected.png
similarity index 100%
rename from res/drawable-finger/btn_circle_selected.png
rename to res/drawable-mdpi-finger/btn_circle_selected.png
Binary files differ
diff --git a/res/drawable/app_icon.png b/res/drawable-mdpi/app_icon.png
similarity index 100%
rename from res/drawable/app_icon.png
rename to res/drawable-mdpi/app_icon.png
Binary files differ
diff --git a/res/drawable/bg_cal_card.9.png b/res/drawable-mdpi/bg_cal_card.9.png
similarity index 100%
rename from res/drawable/bg_cal_card.9.png
rename to res/drawable-mdpi/bg_cal_card.9.png
Binary files differ
diff --git a/res/drawable/box_appointment_normal.9.png b/res/drawable-mdpi/box_appointment_normal.9.png
similarity index 100%
rename from res/drawable/box_appointment_normal.9.png
rename to res/drawable-mdpi/box_appointment_normal.9.png
Binary files differ
diff --git a/res/drawable/box_appointment_pressed.9.png b/res/drawable-mdpi/box_appointment_pressed.9.png
similarity index 100%
rename from res/drawable/box_appointment_pressed.9.png
rename to res/drawable-mdpi/box_appointment_pressed.9.png
Binary files differ
diff --git a/res/drawable/box_appointment_selected.9.png b/res/drawable-mdpi/box_appointment_selected.9.png
similarity index 100%
rename from res/drawable/box_appointment_selected.9.png
rename to res/drawable-mdpi/box_appointment_selected.9.png
Binary files differ
diff --git a/res/drawable/dna_1_of_6.png b/res/drawable-mdpi/dna_1_of_6.png
similarity index 100%
rename from res/drawable/dna_1_of_6.png
rename to res/drawable-mdpi/dna_1_of_6.png
Binary files differ
diff --git a/res/drawable/dna_2345_of_6.png b/res/drawable-mdpi/dna_2345_of_6.png
similarity index 100%
rename from res/drawable/dna_2345_of_6.png
rename to res/drawable-mdpi/dna_2345_of_6.png
Binary files differ
diff --git a/res/drawable/dna_6_of_6.png b/res/drawable-mdpi/dna_6_of_6.png
similarity index 100%
rename from res/drawable/dna_6_of_6.png
rename to res/drawable-mdpi/dna_6_of_6.png
Binary files differ
diff --git a/res/drawable/dna_empty.png b/res/drawable-mdpi/dna_empty.png
similarity index 100%
rename from res/drawable/dna_empty.png
rename to res/drawable-mdpi/dna_empty.png
Binary files differ
diff --git a/res/drawable/ic_alarm_dark.png b/res/drawable-mdpi/ic_alarm_dark.png
similarity index 100%
rename from res/drawable/ic_alarm_dark.png
rename to res/drawable-mdpi/ic_alarm_dark.png
Binary files differ
diff --git a/res/drawable/ic_alarm_white.png b/res/drawable-mdpi/ic_alarm_white.png
similarity index 100%
rename from res/drawable/ic_alarm_white.png
rename to res/drawable-mdpi/ic_alarm_white.png
Binary files differ
diff --git a/res/drawable/ic_btn_round_minus.png b/res/drawable-mdpi/ic_btn_round_minus.png
similarity index 100%
rename from res/drawable/ic_btn_round_minus.png
rename to res/drawable-mdpi/ic_btn_round_minus.png
Binary files differ
diff --git a/res/drawable/ic_btn_round_plus.png b/res/drawable-mdpi/ic_btn_round_plus.png
similarity index 100%
rename from res/drawable/ic_btn_round_plus.png
rename to res/drawable-mdpi/ic_btn_round_plus.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_contact_picture.png b/res/drawable-mdpi/ic_contact_picture.png
new file mode 100644
index 0000000..3a338e8
--- /dev/null
+++ b/res/drawable-mdpi/ic_contact_picture.png
Binary files differ
diff --git a/res/drawable/ic_menu_reminder.png b/res/drawable-mdpi/ic_menu_reminder.png
similarity index 100%
rename from res/drawable/ic_menu_reminder.png
rename to res/drawable-mdpi/ic_menu_reminder.png
Binary files differ
diff --git a/res/drawable/ic_menu_show_list.png b/res/drawable-mdpi/ic_menu_show_list.png
similarity index 100%
rename from res/drawable/ic_menu_show_list.png
rename to res/drawable-mdpi/ic_menu_show_list.png
Binary files differ
diff --git a/res/drawable/ic_repeat_dark.png b/res/drawable-mdpi/ic_repeat_dark.png
similarity index 100%
rename from res/drawable/ic_repeat_dark.png
rename to res/drawable-mdpi/ic_repeat_dark.png
Binary files differ
diff --git a/res/drawable/ic_repeat_white.png b/res/drawable-mdpi/ic_repeat_white.png
similarity index 100%
rename from res/drawable/ic_repeat_white.png
rename to res/drawable-mdpi/ic_repeat_white.png
Binary files differ
diff --git a/res/drawable-mdpi/im_avatar_picture_border_normal.9.png b/res/drawable-mdpi/im_avatar_picture_border_normal.9.png
new file mode 100644
index 0000000..01cc9dc
--- /dev/null
+++ b/res/drawable-mdpi/im_avatar_picture_border_normal.9.png
Binary files differ
diff --git a/res/drawable/month_view_background.9.png b/res/drawable-mdpi/month_view_background.9.png
similarity index 100%
rename from res/drawable/month_view_background.9.png
rename to res/drawable-mdpi/month_view_background.9.png
Binary files differ
diff --git a/res/drawable/month_view_longpress.9.png b/res/drawable-mdpi/month_view_longpress.9.png
similarity index 100%
rename from res/drawable/month_view_longpress.9.png
rename to res/drawable-mdpi/month_view_longpress.9.png
Binary files differ
diff --git a/res/drawable/month_view_pressed.9.png b/res/drawable-mdpi/month_view_pressed.9.png
similarity index 100%
rename from res/drawable/month_view_pressed.9.png
rename to res/drawable-mdpi/month_view_pressed.9.png
Binary files differ
diff --git a/res/drawable/month_view_selected.9.png b/res/drawable-mdpi/month_view_selected.9.png
similarity index 100%
rename from res/drawable/month_view_selected.9.png
rename to res/drawable-mdpi/month_view_selected.9.png
Binary files differ
diff --git a/res/drawable/month_view_today_background.9.png b/res/drawable-mdpi/month_view_today_background.9.png
similarity index 100%
rename from res/drawable/month_view_today_background.9.png
rename to res/drawable-mdpi/month_view_today_background.9.png
Binary files differ
diff --git a/res/drawable/stat_notify_calendar.png b/res/drawable-mdpi/stat_notify_calendar.png
similarity index 100%
rename from res/drawable/stat_notify_calendar.png
rename to res/drawable-mdpi/stat_notify_calendar.png
Binary files differ
diff --git a/res/drawable/sym_calendar_event.png b/res/drawable-mdpi/sym_calendar_event.png
similarity index 100%
rename from res/drawable/sym_calendar_event.png
rename to res/drawable-mdpi/sym_calendar_event.png
Binary files differ
diff --git a/res/layout/agenda_header_footer.xml b/res/layout/agenda_header_footer.xml
new file mode 100644
index 0000000..96824f5
--- /dev/null
+++ b/res/layout/agenda_header_footer.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginLeft="10dip"
+    android:gravity="center_vertical"
+    android:textColor="?android:attr/textColorSecondary"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:paddingLeft="10dip"
+    android:paddingRight="10dip"
+    style="?android:attr/textAppearanceMediumInverse" />
diff --git a/res/layout/contact_item.xml b/res/layout/contact_item.xml
new file mode 100644
index 0000000..86ba140
--- /dev/null
+++ b/res/layout/contact_item.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:paddingLeft="0dip"
+    android:paddingRight="9dip"
+    android:minHeight="48dip">
+
+    <QuickContactBadge
+        android:id="@+id/badge"
+        android:paddingLeft="3dip"
+        android:paddingRight="3dip"
+        android:paddingTop="3dip"
+        android:paddingBottom="6dip"
+        android:layout_above="@+id/separator"
+        android:layout_marginLeft="2dip"
+        android:layout_marginRight="14dip"
+        android:layout_marginTop="4dip"
+        android:layout_marginBottom="3dip"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentTop="true"
+        android:src="@drawable/ic_contact_picture"
+        style="@*android:style/Widget.QuickContactBadgeSmall.WindowSmall" />
+
+    <TextView
+        android:id="@+id/name"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:inputType="none"
+        android:paddingLeft="2dip"
+        android:layout_centerVertical="true"
+        android:layout_toRightOf="@id/badge"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" />
+
+    <ImageView
+        android:id="@+id/presence"
+        android:scaleType="fitXY"
+        android:visibility="gone"
+        android:layout_alignParentRight="true"
+        android:layout_centerVertical="true"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <View
+        android:id="@+id/separator"
+        android:layout_width="fill_parent"
+        android:layout_height="1px"
+        android:layout_alignParentBottom="true"
+        android:background="@android:drawable/divider_horizontal_bright" />
+
+</RelativeLayout>
diff --git a/res/layout/edit_event.xml b/res/layout/edit_event.xml
index 352a4ed..88b92b7 100644
--- a/res/layout/edit_event.xml
+++ b/res/layout/edit_event.xml
@@ -68,14 +68,14 @@
                     android:layout_height="wrap_content"
                     android:layout_weight="7"
                     android:gravity="left|center_vertical"
-                    style="?android:attr/textAppearanceMedium"/>
+                    style="?android:attr/textAppearanceMediumInverse"/>
 
                 <Button android:id="@+id/start_time"
                     android:layout_width="0px"
                     android:layout_height="wrap_content"
                     android:layout_weight="4"
                     android:gravity="left|center_vertical"
-                    style="?android:attr/textAppearanceMedium"/>
+                    style="?android:attr/textAppearanceMediumInverse"/>
 
             </LinearLayout>
 
@@ -95,14 +95,14 @@
                     android:layout_height="wrap_content"
                     android:layout_weight="7"
                     android:gravity="left|center_vertical"
-                    style="?android:attr/textAppearanceMedium"/>
+                    style="?android:attr/textAppearanceMediumInverse"/>
 
                 <Button android:id="@+id/end_time"
                     android:layout_width="0px"
                     android:layout_height="wrap_content"
                     android:layout_weight="4"
                     android:gravity="left|center_vertical"
-                    style="?android:attr/textAppearanceMedium"/>
+                    style="?android:attr/textAppearanceMediumInverse"/>
             </LinearLayout>
 
             <LinearLayout
@@ -116,7 +116,7 @@
                     android:text="@string/edit_event_all_day_label"
                     android:paddingTop="1dip"
                     android:paddingRight="7dip"
-                    style="?android:attr/textAppearanceMedium"/>
+                    style="?android:attr/textAppearanceMediumInverse"/>
                 <CheckBox android:id="@+id/is_all_day"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
@@ -192,7 +192,31 @@
 
             <Spinner android:id="@+id/calendars"
                 android:layout_width="fill_parent"
-                android:layout_height="wrap_content" />
+                android:layout_height="wrap_content"
+                android:prompt="@string/edit_event_calendar_label"/>
+        </LinearLayout>
+
+        <!-- GUESTS/ATTENDEES -->
+        <LinearLayout android:id="@+id/attendees_group"
+            android:orientation="vertical"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            style="@style/EditEvent_Layout">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/attendees_label"
+                style="@style/TextAppearance.EditEvent_Label"/>
+
+            <MultiAutoCompleteTextView android:id="@+id/attendees"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:inputType="textEmailAddress|textMultiLine"
+                android:hint="@string/hint_attendees"
+                android:layout_marginTop="6dip"
+                android:layout_marginBottom="6dip"
+                android:imeOptions="actionNext"/>
         </LinearLayout>
 
         <!-- REPEATS -->
@@ -210,7 +234,8 @@
 
             <Spinner android:id="@+id/repeats"
                 android:layout_width="fill_parent"
-                android:layout_height="wrap_content"/>
+                android:layout_height="wrap_content"
+                android:prompt="@string/repeats_label"/>
         </LinearLayout>
 
         <!-- MORE OPTIONS -->
@@ -236,7 +261,8 @@
                 <Spinner android:id="@+id/availability"
                     android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
-                    android:entries="@array/availability" />
+                    android:entries="@array/availability"
+                    android:prompt="@string/presence_label"/>
             </LinearLayout>
 
             <!-- PRIVACY -->
@@ -255,7 +281,8 @@
                 <Spinner android:id="@+id/visibility"
                     android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
-                    android:entries="@array/visibility" />
+                    android:entries="@array/visibility"
+                    android:prompt="@string/privacy_label"/>
             </LinearLayout>
         </LinearLayout>
 
@@ -294,7 +321,8 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginRight="2dip"
-                android:text="@string/add_new_reminder"/>
+                android:text="@string/add_new_reminder"
+                style="?android:attr/textAppearanceSmallInverse"/>
 
             <ImageButton android:id="@+id/reminder_add"
                 style="@style/PlusButton"
diff --git a/res/layout/event_info_activity.xml b/res/layout/event_info_activity.xml
index 3992e80..a431919 100644
--- a/res/layout/event_info_activity.xml
+++ b/res/layout/event_info_activity.xml
@@ -119,7 +119,30 @@
                     android:autoLink="all"
                     style="?android:attr/textAppearanceSmall"
                 />
+
+                <!-- Organizer -->
+                <LinearLayout android:id="@+id/organizer_container"
+                    android:orientation="horizontal"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:paddingBottom="5dip"
+                >
+            
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginRight="5dip"
+                        android:text="@string/view_event_organizer_label"
+                        style="?android:attr/textAppearanceSmall"
+                    />
     
+                    <TextView android:id="@+id/organizer"
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        style="?android:attr/textAppearanceSmall"
+                    />
+                </LinearLayout>
+
                 <!-- DESCRIPTION -->
                 <TextView android:id="@+id/description"
                     android:layout_width="fill_parent"
@@ -154,7 +177,7 @@
                 </LinearLayout>
             </LinearLayout>
         </LinearLayout>
-        
+
         <!-- RESPONSE -->
         <LinearLayout android:id="@+id/response_container"
             android:orientation="vertical"
@@ -169,7 +192,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:text="@string/view_event_response_label"
-                style="@style/TextAppearance.EditEvent_Label"/>
+                style="@style/TextAppearance.EventInfo_Label"/>
         
             <Spinner android:id="@+id/response_value"
                 style="?android:attr/textAppearanceMedium"
@@ -179,6 +202,14 @@
                 android:entries="@array/response_labels1"/>
         </LinearLayout>
         
+        <!-- GUEST LIST -->
+        <LinearLayout
+            android:id="@+id/attendee_list"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:paddingLeft="8dip"
+            android:orientation="vertical" />
+
         <!-- REMINDERS -->
         <LinearLayout android:id="@+id/reminders_container"
             android:orientation="vertical"
@@ -187,13 +218,13 @@
             android:paddingLeft="8dip"
             android:paddingRight="7dip"
             android:paddingTop="5dip"
-            android:paddingBottom="1dip">
+            android:paddingBottom="5dip">
         
             <TextView android:id="@+id/reminders_label"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:text="@string/reminders_label"
-                style="@style/TextAppearance.EditEvent_Label"/>
+                style="@style/TextAppearance.EventInfo_Label"/>
 
             <LinearLayout android:id="@+id/reminder_items_container"
                 style="?android:attr/textAppearanceMedium"
@@ -201,26 +232,23 @@
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content">
             </LinearLayout>
-        </LinearLayout>
-        <LinearLayout
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:gravity="center_vertical|right"
-            android:paddingRight="5dip"
-            android:paddingBottom="5dip">
-
-            <TextView
-                android:layout_width="wrap_content"
+            <LinearLayout android:id="@+id/reminder_adder"
+                android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
-                android:layout_marginRight="7dip"
-                android:text="@string/add_new_reminder"/>
+                android:gravity="center_vertical|right">
 
-            <ImageButton android:id="@+id/reminder_add"
-                style="@style/PlusButton"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginRight="2dip"
-            />
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginRight="7dip"
+                    android:text="@string/add_new_reminder"/>
+
+                <ImageButton android:id="@+id/reminder_add"
+                    style="@style/PlusButton"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                />
+            </LinearLayout>
         </LinearLayout>
     </LinearLayout>
 </ScrollView>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 5616b49..eb4591d 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"Co"</string>
     <string name="when_label" msgid="894636567327261599">"Kdy"</string>
     <string name="where_label" msgid="3472482206065595118">"Kde"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Hosté"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Opakování"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(Bez předmětu)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Název události"</string>
     <string name="hint_where" msgid="3116239630502213241">"Místo události"</string>
     <string name="hint_description" msgid="4198202812240544553">"Popis události"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"E-mailové adresy"</string>
     <string name="creating_event" msgid="8237877638457604455">"Vytváření události…"</string>
     <string name="saving_event" msgid="8853425146353785688">"Ukládání události…"</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"Načítání kalendářů"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Zobrazit další možnosti"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Skrýt další možnosti"</string>
     <string name="description_label" msgid="7193475046717505855">"Popis"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Účast"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"Přístupnost"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Připomenutí"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"Žádné kalendáře"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"Nemáte žádné kalendáře."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Kalendář"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Organizátor"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Místní časové pásmo"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"Zúčastníte se?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"Dnes"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"Dnes, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"Načítání..."</string>
+    <string name="show_older_events" msgid="4031960000704544741">"Zobrazují se události od <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>. Další položky zobrazíte klepnutím."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"Zobrazují se události do <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>. Další položky zobrazíte klepnutím."</string>
     <string name="num_events" msgid="3351672964607162257">"Počet událostí"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Upravit událost"</string>
     <string name="delete_label" msgid="874742811918030739">"Smazat"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 71f9bed..7f88d90 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"Hvad"</string>
     <string name="when_label" msgid="894636567327261599">"Hvornår"</string>
     <string name="where_label" msgid="3472482206065595118">"Hvor"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Gæster"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Gentagelse"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(Intet emne)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Begivenhedens navn"</string>
     <string name="hint_where" msgid="3116239630502213241">"Begivenhedens placering"</string>
     <string name="hint_description" msgid="4198202812240544553">"Beskrivelse af begivenhed"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"E-mail-adresser"</string>
     <string name="creating_event" msgid="8237877638457604455">"Opretter begivenhed ..."</string>
     <string name="saving_event" msgid="8853425146353785688">"Gemmer begivenhed ..."</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"Indlæser kalendere"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Vis ekstra valgmuligheder"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Skjul ekstra valgmuligheder"</string>
     <string name="description_label" msgid="7193475046717505855">"Beskrivelse"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Tilstedeværelse"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"Fortrolighed"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Påmindelser"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"Der er ingen kalendere"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"Du har ingen kalendere."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Kalender"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Organisator"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Lokal tidszone"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"Deltager?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"I dag"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"I dag<xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"Indlæser ..."</string>
+    <string name="show_older_events" msgid="4031960000704544741">"Viser begivenheder siden <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>. Tryk for at lede efter flere."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"Viser begivenheder indtil <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>. Tryk for at lede efter flere."</string>
     <string name="num_events" msgid="3351672964607162257">"Ant. beg."</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Rediger begivenhed"</string>
     <string name="delete_label" msgid="874742811918030739">"Slet"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 73b75c2..356a69b 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"Was"</string>
     <string name="when_label" msgid="894636567327261599">"Wann"</string>
     <string name="where_label" msgid="3472482206065595118">"Wo"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Gäste"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Wiederholung"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(kein Thema)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Terminname"</string>
     <string name="hint_where" msgid="3116239630502213241">"Ort des Termins"</string>
     <string name="hint_description" msgid="4198202812240544553">"Terminbeschreibung"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"E-Mail-Adressen"</string>
     <string name="creating_event" msgid="8237877638457604455">"Termin wird erstellt…"</string>
     <string name="saving_event" msgid="8853425146353785688">"Termin wird gespeichert…"</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"Kalender werden geladen."</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Zusätzliche Optionen anzeigen"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Zusätzliche Optionen ausblenden"</string>
     <string name="description_label" msgid="7193475046717505855">"Beschreibung"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Status"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"Datenschutz"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Erinnerungen"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"Keine Kalender"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"Sie haben keine Kalender."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Kalender"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Organizer"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Lokalzeit"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"Teilnahme?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"Heute"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"Heute, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"Ladevorgang läuft..."</string>
+    <string name="show_older_events" msgid="4031960000704544741">"Termine seit <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g> werden angezeigt. Tippen Sie, um die Suche zu erweitern."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"Termine bis <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g> werden angezeigt. Tippen Sie, um die Suche zu erweitern."</string>
     <string name="num_events" msgid="3351672964607162257">"Anzahl Termine"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Termin bearbeiten"</string>
     <string name="delete_label" msgid="874742811918030739">"Löschen"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index b8fbc7e..8150930 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"Τι"</string>
     <string name="when_label" msgid="894636567327261599">"Πότε"</string>
     <string name="where_label" msgid="3472482206065595118">"Που"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Προσκεκλημένοι"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Επανάληψη"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(Χωρίς θέμα)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Όνομα συμβάντος"</string>
     <string name="hint_where" msgid="3116239630502213241">"Τοποθεσία συμβάντος"</string>
     <string name="hint_description" msgid="4198202812240544553">"Περιγραφή συμβάντος"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"Διευθύνσεις ηλεκτρονικού ταχυδρομείου"</string>
     <string name="creating_event" msgid="8237877638457604455">"Δημιουργία συμβάντος..."</string>
     <string name="saving_event" msgid="8853425146353785688">"Αποθήκευση συμβάντος…"</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"Φόρτωση ημερολογίων"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Εμφάνιση επιπρόσθετων επιλογών"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Απόκρυψη επιπρόσθετων επιλογών"</string>
     <string name="description_label" msgid="7193475046717505855">"Περιγραφή"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Παρουσία"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"Απόρρητο"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Υπενθυμίσεις"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"Δεν υπάρχουν ημερολόγια"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"Δεν έχετε ημερολόγια."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Ημερολόγιο"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Διοργανωτής"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Τοπική ζώνη ώρας"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"Θα παραβρεθείτε;"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"Σήμερα"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"Σήμερα, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"Φόρτωση..."</string>
+    <string name="show_older_events" msgid="4031960000704544741">"Προβολή συμβάντων από <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>. Πατήστε για να αναζητήσετε περισσότερα συμβάντα."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"Προβολή συμβάντων έως <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>. Αγγίξτε για να αναζητήσετε περισσότερα."</string>
     <string name="num_events" msgid="3351672964607162257">"Αριθμ. συμβάντων"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Επεξεργασία συμβάντος"</string>
     <string name="delete_label" msgid="874742811918030739">"Διαγραφή"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 16d69be..7761958 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -16,10 +16,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="5452708708398908131">"Calendario"</string>
-    <string name="calendar_plug" msgid="8148614847911924208"><font fgcolor="#ffffffff">"¡Bienvenido a Google Calendar!"</font>" "\n" Un método de Google para administrar tu programación basado en la idea de que programar los eventos puede ser más intuitivo, eficaz y accesible."</string>
+    <string name="calendar_plug" msgid="4861031284038774007"><font fgcolor="#ffffffff">"¡Bienvenido a Google Calendar!"</font>" "\n" Un método de Google para administrar tu programación basado en la idea de que programar los eventos puede ser más intuitivo, eficaz y accesible."</string>
     <string name="what_label" msgid="1933578391985810049">"Qué"</string>
     <string name="when_label" msgid="894636567327261599">"Cuándo"</string>
     <string name="where_label" msgid="3472482206065595118">"Dónde"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Invitados"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Repetición"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(Sin asunto)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Nombre del evento"</string>
     <string name="hint_where" msgid="3116239630502213241">"Ubicación del evento"</string>
     <string name="hint_description" msgid="4198202812240544553">"Descripción del evento"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"Direcciones de correo electrónico"</string>
     <string name="creating_event" msgid="8237877638457604455">"Creando evento…"</string>
     <string name="saving_event" msgid="8853425146353785688">"Guardando evento…"</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"Cargando calendarios"</string>
@@ -78,15 +81,19 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Mostrar opciones adicionales"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Ocultar opciones adicionales"</string>
     <string name="description_label" msgid="7193475046717505855">"Descripción"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Presencia"</string>
+    <string name="presence_label" msgid="6169724148441175862">"Mostrarme como"</string>
     <string name="privacy_label" msgid="9215031965259597335">"Privacidad"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Recordatorios"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"No hay calendarios"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"No tienes calendarios."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Calendario"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Organizador"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Zona horaria local"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"¿Asistirás?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"Hoy"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"Hoy, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"Cargando…"</string>
+    <string name="show_older_events" msgid="4031960000704544741">"Mostrando eventos desde <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>. Presionar para buscar más."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"Mostrando eventos hasta <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>. Presionar para buscar más."</string>
     <string name="num_events" msgid="3351672964607162257">"Cant. de eventos"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Editar evento"</string>
     <string name="delete_label" msgid="874742811918030739">"Suprimir"</string>
@@ -118,7 +125,7 @@
     <string name="preferences_alerts_type_dialog" msgid="2195667763429994271">"Alertas y notificaciones"</string>
     <string name="preferences_alerts_vibrate_title" msgid="7997122314759645350">"Vibrar"</string>
     <string name="preferences_alerts_ringtone_title" msgid="7565118268120729644">"Seleccionar tono de llamada"</string>
-    <string name="preferences_default_reminder_title" msgid="103964814265989503">"Config. recordatorio predet."</string>
+    <string name="preferences_default_reminder_title" msgid="5188861433342733905">"Hora predeterminada de recordatorio"</string>
     <string name="preferences_default_reminder_dialog" msgid="2490348857239323412">"Hora predeterminada de recordatorio"</string>
     <string name="preferences_default_reminder_default" msgid="2903884416749959435">"10"</string>
 </resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 9d8ad24..04ee71f 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"Asunto"</string>
     <string name="when_label" msgid="894636567327261599">"Cuándo"</string>
     <string name="where_label" msgid="3472482206065595118">"Dónde"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Invitados"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Repetición"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(Sin asunto)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Nombre del evento"</string>
     <string name="hint_where" msgid="3116239630502213241">"Ubicación del evento"</string>
     <string name="hint_description" msgid="4198202812240544553">"Descripción del evento"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"Direcciones de correo electrónico"</string>
     <string name="creating_event" msgid="8237877638457604455">"Creando evento..."</string>
     <string name="saving_event" msgid="8853425146353785688">"Guardando evento..."</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"Cargando calendarios"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Mostrar opciones extra"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Ocultar opciones extra"</string>
     <string name="description_label" msgid="7193475046717505855">"Descripción"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Presencia"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"Privacidad"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Recordatorios"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"No hay calendarios."</string>
     <string name="no_calendars_found" msgid="755379468136462058">"No tienes ningún calendario."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Calendario"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Organizador"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Zona horaria local"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"¿Asistiendo?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"Hoy"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"Hoy, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"Cargando..."</string>
+    <string name="show_older_events" msgid="4031960000704544741">"Mostrando eventos a partir del <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>. Toca aquí para buscar más."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"Mostrando eventos hasta el <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>. Toca aquí para buscar más."</string>
     <string name="num_events" msgid="3351672964607162257">"Número de eventos"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Editar evento"</string>
     <string name="delete_label" msgid="874742811918030739">"Eliminar"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index e4bf32f..771239d 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"Objet"</string>
     <string name="when_label" msgid="894636567327261599">"Date"</string>
     <string name="where_label" msgid="3472482206065595118">"Lieu"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Invités"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Fréquence"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(Aucun objet)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Nom de l\'événement"</string>
     <string name="hint_where" msgid="3116239630502213241">"Lieu de l\'événement"</string>
     <string name="hint_description" msgid="4198202812240544553">"Description de l\'événement"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"Adresses e-mail"</string>
     <string name="creating_event" msgid="8237877638457604455">"Création de l\'événement…"</string>
     <string name="saving_event" msgid="8853425146353785688">"Enregistrement de l\'événement…"</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"Chargement des agendas"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Afficher les options supplémentaires"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Masquer options supplémentaires"</string>
     <string name="description_label" msgid="7193475046717505855">"Description"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Présence"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"Confidentialité"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Rappels"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"Pas d\'agenda"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"Vous n\'avez pas d\'agenda."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Agenda"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Organisateur"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Fuseau horaire local"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"Participation ?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"Aujourd\'hui"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"Aujourd\'hui, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"Chargement…"</string>
+    <string name="show_older_events" msgid="4031960000704544741">"Affichage des événements depuis <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>. Appuyez pour en consulter d\'autres."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"Affichage des événements jusqu\'à <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>. Appuyez pour en consulter d\'autres."</string>
     <string name="num_events" msgid="3351672964607162257">"Nbre d\'événements"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Modifier l\'événement"</string>
     <string name="delete_label" msgid="874742811918030739">"Supprimer"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index d0ff1e5..dba6d9b 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"Che cosa"</string>
     <string name="when_label" msgid="894636567327261599">"Intervallo di tempo"</string>
     <string name="where_label" msgid="3472482206065595118">"Dove"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Invitati"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Ripetizione"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(Nessun oggetto)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Nome evento"</string>
     <string name="hint_where" msgid="3116239630502213241">"Luogo evento"</string>
     <string name="hint_description" msgid="4198202812240544553">"Descrizione evento"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"Indirizzi email"</string>
     <string name="creating_event" msgid="8237877638457604455">"Creazione evento in corso…"</string>
     <string name="saving_event" msgid="8853425146353785688">"Salvataggio evento in corso…"</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"Caricamento calendari"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Mostra opzioni aggiuntive"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Nascondi opzioni aggiuntive"</string>
     <string name="description_label" msgid="7193475046717505855">"Descrizione"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Presenza"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"Privacy"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Promemoria"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"Nessun calendario"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"Non sono presenti calendari."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Calendario"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Organizzatore"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Fuso orario locale"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"Partecipanti?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"Oggi"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"Oggi, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"Caricamento..."</string>
+    <string name="show_older_events" msgid="4031960000704544741">"Eventi visualizzati a partire da <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>. Tocca per cercarne altri."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"Eventi visualizzati fino a <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>. Tocca per cercarne altri."</string>
     <string name="num_events" msgid="3351672964607162257">"N. eventi"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Modifica  evento"</string>
     <string name="delete_label" msgid="874742811918030739">"Elimina"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index fb83479..dfabb31 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"タイトル"</string>
     <string name="when_label" msgid="894636567327261599">"日時"</string>
     <string name="where_label" msgid="3472482206065595118">"場所"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"ゲスト"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g>(<xliff:g id="GUEST_COUNT">%d</xliff:g>名)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"繰り返し"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(無題)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"タイトル"</string>
     <string name="hint_where" msgid="3116239630502213241">"場所"</string>
     <string name="hint_description" msgid="4198202812240544553">"内容"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"メールアドレス"</string>
     <string name="creating_event" msgid="8237877638457604455">"予定を作成中..."</string>
     <string name="saving_event" msgid="8853425146353785688">"予定を保存中..."</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"カレンダーを読み込み中"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"詳細項目を表示する"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"詳細項目を表示しない"</string>
     <string name="description_label" msgid="7193475046717505855">"内容"</string>
-    <string name="presence_label" msgid="2155381988163502023">"ステータス"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"公開設定"</string>
     <string name="reminders_label" msgid="8345054160145333166">"通知"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"カレンダーがありません"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"カレンダーがありません。"</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"カレンダー"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"主催者"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"ローカルタイムゾーン"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"参加しますか?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"今日"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"今日: <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"読み込み中..."</string>
+    <string name="show_older_events" msgid="4031960000704544741">"<xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>以降の予定を表示しています。タップするとそれ以外の予定を表示します。"</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"<xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>までの予定を表示しています。タップするとそれ以外の予定を表示します。"</string>
     <string name="num_events" msgid="3351672964607162257">"予定数"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"予定を編集"</string>
     <string name="delete_label" msgid="874742811918030739">"削除"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 95e1fb8..74d3f7a 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"내용"</string>
     <string name="when_label" msgid="894636567327261599">"일시"</string>
     <string name="where_label" msgid="3472482206065595118">"장소"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"참석자"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g>(<xliff:g id="GUEST_COUNT">%d</xliff:g>개)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"반복"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(제목 없음)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"일정 이름"</string>
     <string name="hint_where" msgid="3116239630502213241">"일정 장소"</string>
     <string name="hint_description" msgid="4198202812240544553">"일정 설명"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"이메일 주소"</string>
     <string name="creating_event" msgid="8237877638457604455">"일정을 만드는 중..."</string>
     <string name="saving_event" msgid="8853425146353785688">"일정 저장 중..."</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"캘린더 로드 중"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"나머지 옵션 표시"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"나머지 옵션 숨기기"</string>
     <string name="description_label" msgid="7193475046717505855">"설명"</string>
-    <string name="presence_label" msgid="2155381988163502023">"상태"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"공개여부"</string>
     <string name="reminders_label" msgid="8345054160145333166">"알림"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"캘린더 없음"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"캘린더가 없습니다."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"캘린더"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"주최자"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"현지 시간대"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"참석하시겠습니까?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"오늘"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"오늘, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"로드 중..."</string>
+    <string name="show_older_events" msgid="4031960000704544741">"<xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g> 이후의 일정을 표시 중입니다. 더 보려면 누르세요."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"<xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>까지의 일정을 표시 중입니다. 더 보려면 누르세요."</string>
     <string name="num_events" msgid="3351672964607162257">"일정 개수"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"일정 수정"</string>
     <string name="delete_label" msgid="874742811918030739">"삭제"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index c74c58a..6e1035a 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"Hva"</string>
     <string name="when_label" msgid="894636567327261599">"Når"</string>
     <string name="where_label" msgid="3472482206065595118">"Hvor"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Gjester"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Gjentas"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(Mangler emne)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Navn på hendelse"</string>
     <string name="hint_where" msgid="3116239630502213241">"Sted"</string>
     <string name="hint_description" msgid="4198202812240544553">"Beskrivelse av hendelsen"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"E-postadresser"</string>
     <string name="creating_event" msgid="8237877638457604455">"Lager hendelse…"</string>
     <string name="saving_event" msgid="8853425146353785688">"Lagrer hendelse…"</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"Laster kalendre"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Vis ekstra valg"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Skjul ekstra valg"</string>
     <string name="description_label" msgid="7193475046717505855">"Beskrivelse"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Vis meg som"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"Personvern"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Påminnelser"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"Ingen kalendre"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"Du har ingen kalendre."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Kalender"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Arrangør"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Lokal tidssone"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"Kommer du?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"I dag"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"I dag, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"Laster inn ..."</string>
+    <string name="show_older_events" msgid="4031960000704544741">"Viser hendelser siden <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>. Trykk for å se etter flere."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"Viser hendelser inntil <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>. Trykk for å se etter flere."</string>
     <string name="num_events" msgid="3351672964607162257">"Ant. hendelser"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Rediger hendelse"</string>
     <string name="delete_label" msgid="874742811918030739">"Slett"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index cea5a51..c20e8ad 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"Wat"</string>
     <string name="when_label" msgid="894636567327261599">"Wanneer"</string>
     <string name="where_label" msgid="3472482206065595118">"Waar"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Gasten"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Herhaling"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(Geen onderwerp)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Afspraaknaam"</string>
     <string name="hint_where" msgid="3116239630502213241">"Locatie van de afspraak"</string>
     <string name="hint_description" msgid="4198202812240544553">"Beschrijving van afspraak"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"E-mailadressen"</string>
     <string name="creating_event" msgid="8237877638457604455">"Afspraak wordt gemaakt…"</string>
     <string name="saving_event" msgid="8853425146353785688">"Afspraak wordt opgeslagen..."</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"Agenda\'s worden geladen"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Extra opties weergeven"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Extra opties verbergen"</string>
     <string name="description_label" msgid="7193475046717505855">"Beschrijving"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Beschikbaarheid"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"Privacy"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Herinneringen"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"Geen agenda\'s"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"U heeft geen agenda\'s."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Agenda"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Organisator"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Lokale tijdzone"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"Aanwezig?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"Vandaag"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"Vandaag, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"Laden..."</string>
+    <string name="show_older_events" msgid="4031960000704544741">"Afspraken weergeven sinds <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>. Tik om er meer te zoeken."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"Afspraken weergeven tot <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>. Tik om er meer te zoeken."</string>
     <string name="num_events" msgid="3351672964607162257">"Aantal afspraken"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Afspraak bewerken"</string>
     <string name="delete_label" msgid="874742811918030739">"Verwijderen"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 9f89049..bf41ee2 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"Co"</string>
     <string name="when_label" msgid="894636567327261599">"Kiedy"</string>
     <string name="where_label" msgid="3472482206065595118">"Gdzie"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Goście"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Powtórzenie"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(Brak tematu)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Nazwa wydarzenia"</string>
     <string name="hint_where" msgid="3116239630502213241">"Lokalizacja wydarzenia"</string>
     <string name="hint_description" msgid="4198202812240544553">"Opis wydarzenia"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"Adresy e-mail"</string>
     <string name="creating_event" msgid="8237877638457604455">"Tworzenie wydarzenia..."</string>
     <string name="saving_event" msgid="8853425146353785688">"Zapisywanie wydarzenia..."</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"Ładowanie kalendarzy"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Pokaż dodatkowe opcje"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Ukryj dodatkowe opcje"</string>
     <string name="description_label" msgid="7193475046717505855">"Opis"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Obecność"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"Prywatność"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Przypomnienia"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"Brak kalendarzy"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"Nie masz kalendarzy."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Kalendarz"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Organizator"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Lokalna strefa czasowa"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"Uczestnictwo"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"Dzisiaj"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"Dzisiaj, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"Trwa wczytywanie..."</string>
+    <string name="show_older_events" msgid="4031960000704544741">"Pokazywanie wydarzeń od dnia <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>. Dotknij, aby wyszukać więcej."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"Pokazywanie wydarzeń do dnia <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>. Dotknij, aby wyszukać więcej."</string>
     <string name="num_events" msgid="3351672964607162257">"Liczba wydarzeń"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Edytuj wydarzenie"</string>
     <string name="delete_label" msgid="874742811918030739">"Usuń"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 613b002..9d6f55a 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"O quê"</string>
     <string name="when_label" msgid="894636567327261599">"Quando"</string>
     <string name="where_label" msgid="3472482206065595118">"Onde"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Convidados"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Repetição"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(Sem assunto)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Nome do evento"</string>
     <string name="hint_where" msgid="3116239630502213241">"Localização do evento"</string>
     <string name="hint_description" msgid="4198202812240544553">"Descrição do evento"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"Endereços de e-mail"</string>
     <string name="creating_event" msgid="8237877638457604455">"A criar evento..."</string>
     <string name="saving_event" msgid="8853425146353785688">"A guardar evento..."</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"A carregar calendários"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Mostrar opções extra"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Ocultar opções extra"</string>
     <string name="description_label" msgid="7193475046717505855">"Descrição"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Presença"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"Privacidade"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Lembretes"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"Sem calendários"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"Não tem calendários."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Calendário"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Organizador"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Fuso horário local"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"Assistir?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"Hoje"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"Hoje, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"A carregar..."</string>
+    <string name="show_older_events" msgid="4031960000704544741">"A mostrar eventos desde <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>. Toque para procurar mais."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"A mostrar eventos até <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>. Toque para procurar mais."</string>
     <string name="num_events" msgid="3351672964607162257">"N.º de eventos"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Editar evento"</string>
     <string name="delete_label" msgid="874742811918030739">"Eliminar"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index e9a3cba..f38e030 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"O que"</string>
     <string name="when_label" msgid="894636567327261599">"Quando"</string>
     <string name="where_label" msgid="3472482206065595118">"Onde"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Convidados"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Repetições"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(Sem título)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Nome do evento"</string>
     <string name="hint_where" msgid="3116239630502213241">"Local do evento"</string>
     <string name="hint_description" msgid="4198202812240544553">"Descrição do evento"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"Endereços de e-mail"</string>
     <string name="creating_event" msgid="8237877638457604455">"Criando um evento…"</string>
     <string name="saving_event" msgid="8853425146353785688">"Salvando evento…"</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"Carregando as agendas"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Mostrar opções extras"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Ocultar opções extras"</string>
     <string name="description_label" msgid="7193475046717505855">"Descrição"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Presença"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"Privacidade"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Lembretes"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"Nenhuma agenda disponível"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"Você não tem nenhuma agenda."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Agenda"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Organizador"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Localizar fuso horário"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"Você participará?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"Hoje"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"Hoje, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"Carregando..."</string>
+    <string name="show_older_events" msgid="4031960000704544741">"Mostrando eventos desde <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>. Toque para procurar mais."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"Mostrando eventos até <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>. Toque para procurar mais."</string>
     <string name="num_events" msgid="3351672964607162257">"Núm. eventos"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Editar evento"</string>
     <string name="delete_label" msgid="874742811918030739">"Excluir"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index ec87fc2..9612af6 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"Что"</string>
     <string name="when_label" msgid="894636567327261599">"Когда"</string>
     <string name="where_label" msgid="3472482206065595118">"Где"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Гости"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Повторять"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(Без темы)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Название мероприятия"</string>
     <string name="hint_where" msgid="3116239630502213241">"Место мероприятия"</string>
     <string name="hint_description" msgid="4198202812240544553">"Описание мероприятия"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"Адреса электронной почты"</string>
     <string name="creating_event" msgid="8237877638457604455">"Создание мероприятия…"</string>
     <string name="saving_event" msgid="8853425146353785688">"Сохранение мероприятия…"</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"Загрузка календарей"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Показать дополнительные параметры"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Скрыть дополнительные параметры"</string>
     <string name="description_label" msgid="7193475046717505855">"Описание"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Присутствие"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"Конфиденциальность"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Напоминания"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"Нет календарей"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"У вас нет календарей."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Календарь"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Организатор"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Часовой пояс"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"Принять приглашение?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"Сегодня"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"Сегодня, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"Загрузка…"</string>
+    <string name="show_older_events" msgid="4031960000704544741">"Мероприятия с <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>. Нажмите для поиска других мероприятий."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"Мероприятия до <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>. Нажмите для поиска других мероприятий."</string>
     <string name="num_events" msgid="3351672964607162257">"Кол-во мероприятий"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Изменить мероприятие"</string>
     <string name="delete_label" msgid="874742811918030739">"Удалить"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index a343640..2e2502c 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"Vad"</string>
     <string name="when_label" msgid="894636567327261599">"När"</string>
     <string name="where_label" msgid="3472482206065595118">"Var"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Gäster"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Upprepning"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(Inget ämne)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Händelsens namn"</string>
     <string name="hint_where" msgid="3116239630502213241">"Plats för händelsen"</string>
     <string name="hint_description" msgid="4198202812240544553">"Beskrivning av händelse"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"E-postadresser"</string>
     <string name="creating_event" msgid="8237877638457604455">"Skapar händelse…"</string>
     <string name="saving_event" msgid="8853425146353785688">"Sparar händelse…"</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"Läser in kalendrar"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Visa fler alternativ"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Dölj fler alternativ"</string>
     <string name="description_label" msgid="7193475046717505855">"Beskrivning"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Närvaro"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"Sekretess"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Påminnelser"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"Inga kalendrar"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"Du har inga kalendrar."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Kalender"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Organisatör"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Lokal tidszon"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"Delta?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"Idag"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"Idag, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"Hämtar…"</string>
+    <string name="show_older_events" msgid="4031960000704544741">"Visar händelser sedan <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>. Peka om du vill visa fler."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"Visar händelser fram till <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>. Peka om du vill visa fler."</string>
     <string name="num_events" msgid="3351672964607162257">"Antal händelser"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Redigera händelse"</string>
     <string name="delete_label" msgid="874742811918030739">"Ta bort"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 3945dad..25fd812 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"Başlık:"</string>
     <string name="when_label" msgid="894636567327261599">"Zaman:"</string>
     <string name="where_label" msgid="3472482206065595118">"Yer"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"Misafirler"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"Tekrar"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(Konu yok)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"Etkinlik adı"</string>
     <string name="hint_where" msgid="3116239630502213241">"Etkinlik konumu"</string>
     <string name="hint_description" msgid="4198202812240544553">"Etkinlik açıklaması"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"E-posta adresleri"</string>
     <string name="creating_event" msgid="8237877638457604455">"Etkinlik oluşturuluyor..."</string>
     <string name="saving_event" msgid="8853425146353785688">"Etkinlik kaydediliyor..."</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"Takvimler yükleniyor"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"Ek seçenekleri göster"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"Ek seçenekleri gizle"</string>
     <string name="description_label" msgid="7193475046717505855">"Açıklama"</string>
-    <string name="presence_label" msgid="2155381988163502023">"Mevcudiyet"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"Gizlilik"</string>
     <string name="reminders_label" msgid="8345054160145333166">"Hatırlatıcılar"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"Takvim yok"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"Hiç takviminiz yok."</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"Takvim"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"Düzenleyici"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"Yerel saat dilimi"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"Katılıyor musunuz?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"Bugün"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"Bugün, <xliff:g id="DATE">%1$s</xliff:g>"</string>
+    <string name="loading" msgid="3772533493214331230">"Yükleniyor…"</string>
+    <string name="show_older_events" msgid="4031960000704544741">"Etkinlikler <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g> tarihinden itibaren gösteriliyor. Daha fazlasını görmek için hafifçe vurun."</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"Etkinlikler <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g> tarihine kadar gösteriliyor. Daha fazlasını görmek için hafifçe vurun."</string>
     <string name="num_events" msgid="3351672964607162257">"Etkinlik sayısı"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"Etkinliği düzenle"</string>
     <string name="delete_label" msgid="874742811918030739">"Sil"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 6b55f1b..dc1a994 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"内容"</string>
     <string name="when_label" msgid="894636567327261599">"时间"</string>
     <string name="where_label" msgid="3472482206065595118">"地点"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"来宾"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"重复"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(无主题)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"活动名称"</string>
     <string name="hint_where" msgid="3116239630502213241">"活动地点"</string>
     <string name="hint_description" msgid="4198202812240544553">"活动说明"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"电子邮件地址"</string>
     <string name="creating_event" msgid="8237877638457604455">"正在创建活动..."</string>
     <string name="saving_event" msgid="8853425146353785688">"正在保存活动..."</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"正在载入日历"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"显示额外选项"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"隐藏额外选项"</string>
     <string name="description_label" msgid="7193475046717505855">"说明"</string>
-    <string name="presence_label" msgid="2155381988163502023">"状态"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"隐私"</string>
     <string name="reminders_label" msgid="8345054160145333166">"提醒"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"无日历"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"您没有日历。"</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"日历帐户"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"组织者"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"本地时区"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"参加吗?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"今天"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"今天(<xliff:g id="DATE">%1$s</xliff:g>)"</string>
+    <string name="loading" msgid="3772533493214331230">"正在载入..."</string>
+    <string name="show_older_events" msgid="4031960000704544741">"显示自 <xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>以来发生的活动。点按可查看更多活动。"</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"显示 <xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>之前发生的活动。点按可查看更多活动。"</string>
     <string name="num_events" msgid="3351672964607162257">"活动数"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"编辑活动"</string>
     <string name="delete_label" msgid="874742811918030739">"删除"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 69bd446..5ae4980 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -20,6 +20,8 @@
     <string name="what_label" msgid="1933578391985810049">"主題"</string>
     <string name="when_label" msgid="894636567327261599">"時間"</string>
     <string name="where_label" msgid="3472482206065595118">"地點"</string>
+    <string name="attendees_label" msgid="2971281641565729725">"邀請對象"</string>
+    <string name="response_label" msgid="5732943469653254290">"<xliff:g id="RESPONSE_TYPE">%s</xliff:g> (<xliff:g id="GUEST_COUNT">%d</xliff:g>)"</string>
     <string name="repeats_label" msgid="7414023871434593196">"重複頻率"</string>
     <string name="no_title_label" msgid="7352118984125107858">"(無主題)"</string>
   <plurals name="Nminutes">
@@ -59,6 +61,7 @@
     <string name="hint_what" msgid="709155115005044531">"活動名稱"</string>
     <string name="hint_where" msgid="3116239630502213241">"活動地點"</string>
     <string name="hint_description" msgid="4198202812240544553">"活動說明"</string>
+    <string name="hint_attendees" msgid="6036653711383143333">"電子郵件地址"</string>
     <string name="creating_event" msgid="8237877638457604455">"正在建立活動..."</string>
     <string name="saving_event" msgid="8853425146353785688">"正在儲存活動..."</string>
     <string name="loading_calendars_title" msgid="3819254313413902272">"正在載入日曆"</string>
@@ -78,15 +81,20 @@
     <string name="edit_event_show_extra_options" msgid="2325854287823989650">"顯示少用選項"</string>
     <string name="edit_event_hide_extra_options" msgid="4019082307326855513">"隱藏少用選項"</string>
     <string name="description_label" msgid="7193475046717505855">"說明"</string>
-    <string name="presence_label" msgid="2155381988163502023">"狀態"</string>
+    <!-- no translation found for presence_label (6169724148441175862) -->
+    <skip />
     <string name="privacy_label" msgid="9215031965259597335">"隱私權"</string>
     <string name="reminders_label" msgid="8345054160145333166">"提醒"</string>
     <string name="no_syncable_calendars" msgid="7019488867045436129">"無日曆"</string>
     <string name="no_calendars_found" msgid="755379468136462058">"您沒有日曆。"</string>
     <string name="view_event_calendar_label" msgid="8503354404461986250">"日曆"</string>
+    <string name="view_event_organizer_label" msgid="2168441329713325834">"主辦人"</string>
     <string name="view_event_timezone_label" msgid="6461351857281070935">"當地時區"</string>
     <string name="view_event_response_label" msgid="8382281658458798329">"是否參加?"</string>
-    <string name="agenda_today" msgid="2405333795044229594">"今日"</string>
+    <string name="agenda_today" msgid="6489447319363439068">"今天 (<xliff:g id="DATE">%1$s</xliff:g>)"</string>
+    <string name="loading" msgid="3772533493214331230">"載入中..."</string>
+    <string name="show_older_events" msgid="4031960000704544741">"顯示「<xliff:g id="OLDEST_SEARCH_RANGE">%1$s</xliff:g>」之後的活動,輕按以查看更多活動。"</string>
+    <string name="show_newer_events" msgid="2647889653936094369">"顯示「<xliff:g id="NEWEST_SEARCH_RANGE">%1$s</xliff:g>」之前的活動,輕按以查看更多活動。"</string>
     <string name="num_events" msgid="3351672964607162257">"活動數"</string>
     <string name="edit_event_label" msgid="2900418236819088363">"編輯活動"</string>
     <string name="delete_label" msgid="874742811918030739">"刪除"</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e49015e..f733096 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -19,7 +19,7 @@
     <string name="app_label">Calendar</string>
     <!-- This is the welcome message when a user starts Calendar for the first time -->
     <string name="calendar_plug"><font fgcolor="#ffffffff">Welcome to Google Calendar!</font>
-    \nA Google approach to managing your schedule built on the idea that scheduling events can be more intuitive, efficient and accessible.
+    \nA Google approach to managing your schedule built on the idea that scheduling events can be more intuitive, efficient, and accessible.
     </string>
 
     <!-- Shared Labels. These labels are shared among the activities. -->
@@ -30,6 +30,11 @@
     <string name="when_label">When</string>
     <!-- This is the label for the location of an event -->
     <string name="where_label">Where</string>
+    <!-- This is the label for the Guests/Attendees of an event -->
+    <string name="attendees_label">Guests</string>
+    <!-- This is the label for the Guest Responses and count of an event e.g. Yes (3) -->
+    <string name="response_label">"<xliff:g id="response_type">%s</xliff:g> (<xliff:g id="guest_count">%d</xliff:g>)"</string>
+    
     <!-- Some events repeat daily, weekly, monthly, or yearly.  This is the label
          for all the choices about how often an event repeats (including the choice
          of not repeating). -->
@@ -151,6 +156,8 @@
     <string name="hint_where">"Event location"</string>
     <!-- Default value of Description field (as a hint to the user) -->
     <string name="hint_description">"Event description"</string>
+    <!-- Default value of Attendees/Guests field (as a hint to the user) -->
+    <string name="hint_attendees">"Email addresses"</string>
     <string name="creating_event">"Creating event\u2026"</string>
     <string name="saving_event">"Saving event\u2026"</string>
     <string name="loading_calendars_title">"Loading calendars"</string>
@@ -206,7 +213,7 @@
     <string name="description_label">Description</string>
     <!-- Label for the 'Presence' of an event, which can be either 'busy' (the default)
          or 'available' -->
-    <string name="presence_label">Presence</string>
+    <string name="presence_label">Show me as</string>
     <!-- Label for the 'Privacy' of an event, which can be either 'private'
          or 'public' -->
     <string name="privacy_label">Privacy</string>
@@ -219,6 +226,8 @@
     <skip />
     <!-- Label for which calendar an event is part of -->
     <string name="view_event_calendar_label">Calendar</string>
+    <!-- Label for the event organizer -->
+    <string name="view_event_organizer_label">Organizer</string>
     <!-- Label for the local timezone -->
     <string name="view_event_timezone_label">Local time zone</string>
     <!-- Label for whether the user is attending this event. This is shown when
@@ -229,7 +238,13 @@
     <!-- Agenda View strings -->
     <skip />
     <!-- This is shown as part of the heading at the top of a list of today's events. -->
-    <string name="agenda_today">Today</string>
+    <string name="agenda_today">Today, <xliff:g id="date">%1$s</xliff:g></string>
+    <!-- This is shown while the calendar events are being loading to the screen. -->
+    <string name="loading">Loading\u2026</string>
+    <!-- This is shown at the top of the agenda view showing the range of events shown. -->
+    <string name="show_older_events">Showing events since <xliff:g id="oldest_search_range">%1$s</xliff:g>. Tap to look for more.</string>
+    <!-- This is shown at the bottom of the agenda view showing the range of events shown. -->
+    <string name="show_newer_events">Showing events until <xliff:g id="newest_search_range">%1$s</xliff:g>. Tap to look for more.</string>
     
     <!-- ICS Import activity -->
     <skip />
@@ -343,7 +358,7 @@
     <!-- Title of ringtone selector dialog -->
     <string name="preferences_alerts_ringtone_title">Select ringtone</string>
     <!-- List item label for setting the default number of reminder minutes -->
-    <string name="preferences_default_reminder_title">Set default reminder</string>
+    <string name="preferences_default_reminder_title">Default reminder time</string>
     <!-- Title of dialog for setting the default number of reminder minutes -->
     <string name="preferences_default_reminder_dialog">Default reminder time</string>
     <!-- Default value for the number of reminder minutes -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 4471ad2..0f6e89d 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -59,6 +59,13 @@
     
     <style name="TextAppearance.EditEvent_Label">
         <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+        <item name="android:textColor">?android:attr/textColorSecondaryInverse</item>
+        <item name="android:textStyle">bold</item>
+        <item name="android:paddingLeft">2dip</item>
+    </style>
+    
+    <style name="TextAppearance.EventInfo_Label">
+        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
         <item name="android:textColor">?android:attr/textColorSecondary</item>
         <item name="android:textStyle">bold</item>
         <item name="android:paddingLeft">2dip</item>
diff --git a/src/com/android/calendar/AgendaActivity.java b/src/com/android/calendar/AgendaActivity.java
index 00a46af..b414033 100644
--- a/src/com/android/calendar/AgendaActivity.java
+++ b/src/com/android/calendar/AgendaActivity.java
@@ -16,163 +16,44 @@
 
 package com.android.calendar;
 
+import static android.provider.Calendar.EVENT_BEGIN_TIME;
+
 import android.app.Activity;
-import android.content.AsyncQueryHandler;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
-import android.content.ContentUris;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.database.ContentObserver;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.preference.PreferenceManager;
-import android.provider.Calendar;
-import android.provider.Calendar.Attendees;
-import android.provider.Calendar.Calendars;
 import android.provider.Calendar.Events;
-import android.provider.Calendar.Instances;
 import android.text.format.Time;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
-import android.view.View;
-import android.view.Window;
-import android.widget.AdapterView;
-import android.widget.ListView;
-import android.widget.ViewSwitcher;
+
 import dalvik.system.VMRuntime;
 
-public class AgendaActivity extends Activity implements ViewSwitcher.ViewFactory, Navigator {
+public class AgendaActivity extends Activity implements Navigator {
+
+    private static final String TAG = "AgendaActivity";
+
+    private static boolean DEBUG = false;
 
     protected static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time";
 
-    static final String[] PROJECTION = new String[] {
-        Instances._ID,                  // 0
-        Instances.TITLE,                // 1
-        Instances.EVENT_LOCATION,       // 2
-        Instances.ALL_DAY,              // 3
-        Instances.HAS_ALARM,            // 4
-        Instances.COLOR,                // 5
-        Instances.RRULE,                // 6
-        Instances.BEGIN,                // 7
-        Instances.END,                  // 8
-        Instances.EVENT_ID,             // 9
-        Instances.START_DAY,            // 10  Julian start day
-        Instances.END_DAY,              // 11  Julian end day
-        Instances.SELF_ATTENDEE_STATUS, // 12
-    };
-
-    public static final int INDEX_TITLE = 1;
-    public static final int INDEX_EVENT_LOCATION = 2;
-    public static final int INDEX_ALL_DAY = 3;
-    public static final int INDEX_HAS_ALARM = 4;
-    public static final int INDEX_COLOR = 5;
-    public static final int INDEX_RRULE = 6;
-    public static final int INDEX_BEGIN = 7;
-    public static final int INDEX_END = 8;
-    public static final int INDEX_EVENT_ID = 9;
-    public static final int INDEX_START_DAY = 10;
-    public static final int INDEX_END_DAY = 11;
-    public static final int INDEX_SELF_ATTENDEE_STATUS = 12;
-
-    public static final String AGENDA_SORT_ORDER = "startDay ASC, begin ASC, title ASC";
-
     private static final long INITIAL_HEAP_SIZE = 4*1024*1024;
 
     private ContentResolver mContentResolver;
 
-    private ViewSwitcher mViewSwitcher;
+    private AgendaListView mAgendaListView;
 
-    private QueryHandler mQueryHandler;
-    private DeleteEventHelper mDeleteEventHelper;
     private Time mTime;
 
-    /**
-     * This records the start time parameter for the last query sent to the
-     * AsyncQueryHandler so that we don't send it duplicate query requests.
-     */
-    private Time mLastQueryTime = new Time();
-
-    private class QueryHandler extends AsyncQueryHandler {
-        public QueryHandler(ContentResolver cr) {
-            super(cr);
-        }
-
-        @Override
-        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
-
-            // Only set mCursor if the Activity is not finishing. Otherwise close the cursor.
-            if (!isFinishing()) {
-                AgendaListView next = (AgendaListView) mViewSwitcher.getNextView();
-                next.setCursor(cursor);
-                mViewSwitcher.showNext();
-                selectTime();
-            } else {
-                cursor.close();
-            }
-        }
-    }
-
-    private class AgendaListView extends ListView {
-        private Cursor mCursor;
-        private AgendaByDayAdapter mDayAdapter;
-        private AgendaAdapter mAdapter;
-
-        public AgendaListView(Context context) {
-            super(context, null);
-            setOnItemClickListener(mOnItemClickListener);
-            setChoiceMode(ListView.CHOICE_MODE_SINGLE);
-            mAdapter = new AgendaAdapter(AgendaActivity.this, R.layout.agenda_item);
-            mDayAdapter = new AgendaByDayAdapter(AgendaActivity.this, mAdapter);
-        }
-
-        public void setCursor(Cursor cursor) {
-            if (mCursor != null) {
-                mCursor.close();
-            }
-            mCursor = cursor;
-            mDayAdapter.calculateDays(cursor);
-            mAdapter.changeCursor(cursor);
-            setAdapter(mDayAdapter);
-        }
-
-        public Cursor getCursor() {
-            return mCursor;
-        }
-
-        public AgendaByDayAdapter getDayAdapter() {
-            return mDayAdapter;
-        }
-
-        @Override protected void onDetachedFromWindow() {
-            super.onDetachedFromWindow();
-            if (mCursor != null) {
-                mCursor.close();
-            }
-        }
-
-        private OnItemClickListener mOnItemClickListener = new OnItemClickListener() {
-            public void onItemClick(AdapterView a, View v, int position, long id) {
-                if (id != -1) {
-                    // Switch to the EventInfo view
-                    mCursor.moveToPosition(mDayAdapter.getCursorPosition(position));
-                    long eventId = mCursor.getLong(INDEX_EVENT_ID);
-                    Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId);
-                    Intent intent = new Intent(Intent.ACTION_VIEW, uri);
-                    intent.putExtra(Calendar.EVENT_BEGIN_TIME, mCursor.getLong(INDEX_BEGIN));
-                    intent.putExtra(Calendar.EVENT_END_TIME, mCursor.getLong(INDEX_END));
-                    startActivity(intent);
-                }
-            }
-        };
-    }
-
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -180,8 +61,7 @@
             if (action.equals(Intent.ACTION_TIME_CHANGED)
                     || action.equals(Intent.ACTION_DATE_CHANGED)
                     || action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
-                clearLastQueryTime();
-                renewCursor();
+                mAgendaListView.refresh(true);
             }
         }
     };
@@ -194,56 +74,78 @@
 
         @Override
         public void onChange(boolean selfChange) {
-            clearLastQueryTime();
-            renewCursor();
+            mAgendaListView.refresh(true);
         }
     };
 
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-
+        
         // Eliminate extra GCs during startup by setting the initial heap size to 4MB.
         // TODO: We should restore the old heap size once the activity reaches the idle state
-        long oldHeapSize = VMRuntime.getRuntime().setMinimumHeapSize(INITIAL_HEAP_SIZE);
+        VMRuntime.getRuntime().setMinimumHeapSize(INITIAL_HEAP_SIZE);
 
-        setContentView(R.layout.agenda_activity);
+        mAgendaListView = new AgendaListView(this);
+        setContentView(mAgendaListView);
 
         mContentResolver = getContentResolver();
-        mQueryHandler = new QueryHandler(mContentResolver);
 
-        // Preserve the same month and event selection if this activity is
-        // being restored due to an orientation change
-        mTime = new Time();
-        if (icicle != null) {
-            mTime.set(icicle.getLong(BUNDLE_KEY_RESTORE_TIME));
-        } else {
-            mTime.set(Utils.timeFromIntent(getIntent()));
-        }
         setTitle(R.string.agenda_view);
 
-        mViewSwitcher = (ViewSwitcher) findViewById(R.id.switcher);
-        mViewSwitcher.setFactory(this);
+        long millis = 0;
+        mTime = new Time();
+        if (icicle != null) {
+            // Returns 0 if key not found
+            millis = icicle.getLong(BUNDLE_KEY_RESTORE_TIME);
+            if (DEBUG) {
+                Log.v(TAG, "Restore value from icicle: " + millis);
+            }
+        }
 
-        // Record Agenda View as the (new) default detailed view.
-        String activityString = CalendarApplication.ACTIVITY_NAMES[CalendarApplication.AGENDA_VIEW_ID];
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
-        SharedPreferences.Editor editor = prefs.edit();
-        editor.putString(CalendarPreferenceActivity.KEY_DETAILED_VIEW, activityString);
+        if (millis == 0) {
+            // Returns 0 if key not found
+            millis = getIntent().getLongExtra(EVENT_BEGIN_TIME, 0);
+            if (DEBUG) {
+                Time time = new Time();
+                time.set(millis);
+                Log.v(TAG, "Restore value from intent: " + time.toString());
+            }
+        }
 
-        // Record Agenda View as the (new) start view
-        editor.putString(CalendarPreferenceActivity.KEY_START_VIEW, activityString);
-        editor.commit();
+        if (millis == 0) {
+            if (DEBUG) {
+                Log.v(TAG, "Restored from current time");
+            }
+            millis = System.currentTimeMillis();
+        }
+        mTime.set(millis);
+    }
 
-        mDeleteEventHelper = new DeleteEventHelper(this, false /* don't exit when done */);
+    @Override
+    protected void onNewIntent(Intent intent) {
+        long time = Utils.timeFromIntentInMillis(intent);
+        if (time > 0) {
+            mTime.set(time);
+            goTo(mTime, false);
+        }
     }
 
     @Override
     protected void onResume() {
         super.onResume();
+        if (DEBUG) {
+            Log.v(TAG, "OnResume to " + mTime.toString());
+        }
 
-        clearLastQueryTime();
-        renewCursor();
+        SharedPreferences prefs =
+            PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+        boolean hideDeclined = prefs
+                .getBoolean(CalendarPreferenceActivity.KEY_HIDE_DECLINED, false);
+
+        mAgendaListView.setHideDeclinedEvents(hideDeclined);
+        mAgendaListView.goTo(mTime, true);
+        mAgendaListView.onResume();
 
         // Register for Intent broadcasts
         IntentFilter filter = new IntentFilter();
@@ -259,21 +161,26 @@
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
 
-        outState.putLong(BUNDLE_KEY_RESTORE_TIME, getSelectedTime());
+        long firstVisibleTime = mAgendaListView.getFirstVisibleTime();
+        if (firstVisibleTime > 0) {
+            mTime.set(firstVisibleTime);
+            outState.putLong(BUNDLE_KEY_RESTORE_TIME, firstVisibleTime);
+            if (DEBUG) {
+                Log.v(TAG, "onSaveInstanceState " + mTime.toString());
+            }
+        }
     }
 
     @Override
     protected void onPause() {
         super.onPause();
 
+        mAgendaListView.onPause();
         mContentResolver.unregisterContentObserver(mObserver);
         unregisterReceiver(mIntentReceiver);
 
-        // Clear the cursor so it won't crash when switching orientation while scrolling b/2022729
-        String[] columns = new String[1];
-        columns[0] = "_id";
-        AgendaListView current = (AgendaListView) mViewSwitcher.getCurrentView();
-        current.setCursor(new MatrixCursor(columns));
+        // Record Agenda View as the (new) default detailed view.
+        Utils.setDefaultView(this, CalendarApplication.AGENDA_VIEW_ID);
     }
 
     @Override
@@ -297,135 +204,27 @@
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         switch (keyCode) {
-            case KeyEvent.KEYCODE_DEL: {
+            case KeyEvent.KEYCODE_DEL:
                 // Delete the currently selected event (if any)
-                AgendaListView current = (AgendaListView) mViewSwitcher.getCurrentView();
-                Cursor cursor = current.getCursor();
-                if (cursor != null) {
-                    int position = current.getSelectedItemPosition();
-                    position = current.getDayAdapter().getCursorPosition(position);
-                    if (position >= 0) {
-                        cursor.moveToPosition(position);
-                        long begin = cursor.getLong(INDEX_BEGIN);
-                        long end = cursor.getLong(INDEX_END);
-                        long eventId = cursor.getLong(INDEX_EVENT_ID);
-                        mDeleteEventHelper.delete(begin, end, eventId, -1);
-                    }
-                }
-            }
+                mAgendaListView.deleteSelectedEvent();
                 break;
-
-            case KeyEvent.KEYCODE_BACK:
-                finish();
-                return true;
         }
         return super.onKeyDown(keyCode, event);
     }
 
-    /**
-     * Clears the cached value for the last query time so that renewCursor()
-     * will force a requery of the Calendar events.
-     */
-    private void clearLastQueryTime() {
-        mLastQueryTime.year = 0;
-        mLastQueryTime.month = 0;
-    }
-
-    private void renewCursor() {
-        // Avoid batching up repeated queries for the same month.  This can
-        // happen if the user scrolls with the trackball too fast.
-        if (mLastQueryTime.month == mTime.month && mLastQueryTime.year == mTime.year) {
-            return;
-        }
-
-        // Query all instances for the current month
-        Time time = new Time();
-        time.year = mTime.year;
-        time.month = mTime.month;
-        long start = time.normalize(true);
-
-        time.month++;
-        long end = time.normalize(true);
-
-        StringBuilder path = new StringBuilder();
-        path.append(start);
-        path.append('/');
-        path.append(end);
-
-        // Respect the preference to show/hide declined events
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
-        boolean hideDeclined = prefs.getBoolean(CalendarPreferenceActivity.KEY_HIDE_DECLINED,
-                false);
-
-        Uri uri = Uri.withAppendedPath(Instances.CONTENT_URI, path.toString());
-
-        String selection;
-        if (hideDeclined) {
-            selection = Calendars.SELECTED + "=1 AND " +
-                    Instances.SELF_ATTENDEE_STATUS + "!=" + Attendees.ATTENDEE_STATUS_DECLINED;
-        } else {
-            selection = Calendars.SELECTED + "=1";
-        }
-
-        // Cancel any previous queries that haven't started yet.  This
-        // isn't likely to happen since we already avoid sending
-        // a duplicate query for the same month as the previous query.
-        // But if the user quickly wiggles the trackball back and forth,
-        // he could generate a stream of queries.
-        mQueryHandler.cancelOperation(0);
-
-        mLastQueryTime.month = mTime.month;
-        mLastQueryTime.year = mTime.year;
-        mQueryHandler.startQuery(0, null, uri, PROJECTION, selection, null,
-                AGENDA_SORT_ORDER);
-    }
-
-    private void selectTime() {
-        // Selects the first event of the day
-        AgendaListView current = (AgendaListView) mViewSwitcher.getCurrentView();
-        if (current.getCursor() == null) {
-            return;
-        }
-
-        int position = current.getDayAdapter().findDayPositionNearestTime(mTime);
-        current.setSelection(position);
-    }
-
-    /* ViewSwitcher.ViewFactory interface methods */
-    public View makeView() {
-        AgendaListView agendaListView = new AgendaListView(this);
-        return agendaListView;
-    }
-
     /* Navigator interface methods */
     public void goToToday() {
         Time now = new Time();
         now.set(System.currentTimeMillis());
-        goTo(now);
+        goTo(now, true);
     }
 
-    public void goTo(Time time) {
-        if (mTime.year == time.year && mTime.month == time.month) {
-            mTime = time;
-            selectTime();
-        } else {
-            mTime = time;
-            renewCursor();
-        }
+    public void goTo(Time time, boolean animate) {
+        mAgendaListView.goTo(time, false);
     }
 
     public long getSelectedTime() {
-        // Update the current time based on the selected event
-        AgendaListView current = (AgendaListView) mViewSwitcher.getCurrentView();
-        int position = current.getSelectedItemPosition();
-        position = current.getDayAdapter().getCursorPosition(position);
-        Cursor cursor = current.getCursor();
-        if (position >= 0 && position < cursor.getCount()) {
-            cursor.moveToPosition(position);
-            mTime.set(cursor.getLong(INDEX_BEGIN));
-        }
-
-        return mTime.toMillis(true);
+        return mAgendaListView.getSelectedTime();
     }
 
     public boolean getAllDay() {
diff --git a/src/com/android/calendar/AgendaAdapter.java b/src/com/android/calendar/AgendaAdapter.java
index 1b93b7e..e54e345 100644
--- a/src/com/android/calendar/AgendaAdapter.java
+++ b/src/com/android/calendar/AgendaAdapter.java
@@ -26,10 +26,16 @@
 import android.widget.ResourceCursorAdapter;
 import android.widget.TextView;
 
+import java.util.Formatter;
+import java.util.Locale;
+
 public class AgendaAdapter extends ResourceCursorAdapter {
-    static private String mNoTitleLabel; // todo update on locale change.
+    private String mNoTitleLabel;
     private Resources mResources;
     private int mDeclinedColor;
+    // Note: Formatter is not thread safe. Fine for now as it is only used by the main thread.
+    private Formatter mFormatter;
+    private StringBuilder mStringBuilder;
 
     static class ViewHolder {
         int overLayColor; // Used by AgendaItemView to gray out the entire item if so desired
@@ -46,11 +52,20 @@
         mResources = context.getResources();
         mNoTitleLabel = mResources.getString(R.string.no_title_label);
         mDeclinedColor = mResources.getColor(R.drawable.agenda_item_declined);
+        mStringBuilder = new StringBuilder(50);
+        mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
     }
 
     @Override
     public void bindView(View view, Context context, Cursor cursor) {
-        ViewHolder holder = (ViewHolder) view.getTag();
+        ViewHolder holder = null;
+
+        // Listview may get confused and pass in a different type of view since
+        // we keep shifting data around. Not a big problem.
+        Object tag = view.getTag();
+        if (tag instanceof ViewHolder) {
+            holder = (ViewHolder) view.getTag();
+        }
 
         if (holder == null) {
             holder = new ViewHolder();
@@ -61,7 +76,7 @@
         }
 
         // Fade text if event was declined.
-        int selfAttendeeStatus = cursor.getInt(AgendaActivity.INDEX_SELF_ATTENDEE_STATUS);
+        int selfAttendeeStatus = cursor.getInt(AgendaWindowAdapter.INDEX_SELF_ATTENDEE_STATUS);
         if (selfAttendeeStatus == Attendees.ATTENDEE_STATUS_DECLINED) {
             holder.overLayColor = mDeclinedColor;
         } else {
@@ -73,11 +88,11 @@
         TextView where = holder.where;
 
         /* Calendar Color */
-        int color = cursor.getInt(AgendaActivity.INDEX_COLOR);
+        int color = cursor.getInt(AgendaWindowAdapter.INDEX_COLOR);
         holder.calendarColor = color;
 
         // What
-        String titleString = cursor.getString(AgendaActivity.INDEX_TITLE);
+        String titleString = cursor.getString(AgendaWindowAdapter.INDEX_TITLE);
         if (titleString == null || titleString.length() == 0) {
             titleString = mNoTitleLabel;
         }
@@ -85,9 +100,9 @@
         title.setTextColor(color);
 
         // When
-        long begin = cursor.getLong(AgendaActivity.INDEX_BEGIN);
-        long end = cursor.getLong(AgendaActivity.INDEX_END);
-        boolean allDay = cursor.getInt(AgendaActivity.INDEX_ALL_DAY) != 0;
+        long begin = cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
+        long end = cursor.getLong(AgendaWindowAdapter.INDEX_END);
+        boolean allDay = cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
         int flags;
         String whenString;
         if (allDay) {
@@ -98,10 +113,11 @@
         if (DateFormat.is24HourFormat(context)) {
             flags |= DateUtils.FORMAT_24HOUR;
         }
-        whenString = DateUtils.formatDateRange(context, begin, end, flags);
+        mStringBuilder.setLength(0);
+        whenString = DateUtils.formatDateRange(context, mFormatter, begin, end, flags).toString();
         when.setText(whenString);
 
-        String rrule = cursor.getString(AgendaActivity.INDEX_RRULE);
+        String rrule = cursor.getString(AgendaWindowAdapter.INDEX_RRULE);
         if (rrule != null) {
             when.setCompoundDrawablesWithIntrinsicBounds(null, null,
                     context.getResources().getDrawable(R.drawable.ic_repeat_dark), null);
@@ -130,7 +146,7 @@
         */
 
         // Where
-        String whereString = cursor.getString(AgendaActivity.INDEX_EVENT_LOCATION);
+        String whereString = cursor.getString(AgendaWindowAdapter.INDEX_EVENT_LOCATION);
         if (whereString != null && whereString.length() > 0) {
             where.setVisibility(View.VISIBLE);
             where.setText(whereString);
diff --git a/src/com/android/calendar/AgendaByDayAdapter.java b/src/com/android/calendar/AgendaByDayAdapter.java
index 140eb72..881c1a2 100644
--- a/src/com/android/calendar/AgendaByDayAdapter.java
+++ b/src/com/android/calendar/AgendaByDayAdapter.java
@@ -26,27 +26,39 @@
 import android.widget.BaseAdapter;
 import android.widget.TextView;
 
+import com.android.calendar.AgendaWindowAdapter.DayAdapterInfo;
+
 import java.util.ArrayList;
-import java.util.Calendar;
+import java.util.Formatter;
 import java.util.Iterator;
 import java.util.LinkedList;
+import java.util.Locale;
 
 public class AgendaByDayAdapter extends BaseAdapter {
     private static final int TYPE_DAY = 0;
     private static final int TYPE_MEETING = 1;
-    private static final int TYPE_LAST = 2;
+    static final int TYPE_LAST = 2;
 
     private final Context mContext;
     private final AgendaAdapter mAgendaAdapter;
     private final LayoutInflater mInflater;
     private ArrayList<RowInfo> mRowInfo;
     private int mTodayJulianDay;
-    private Time mTime = new Time();
+    private Time mTmpTime = new Time();
+    // Note: Formatter is not thread safe. Fine for now as it is only used by the main thread.
+    private Formatter mFormatter;
+    private StringBuilder mStringBuilder;
 
-    public AgendaByDayAdapter(Context context, AgendaAdapter agendaAdapter) {
+    static class ViewHolder {
+        TextView dateView;
+    }
+
+    public AgendaByDayAdapter(Context context) {
         mContext = context;
-        mAgendaAdapter = agendaAdapter;
-        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mAgendaAdapter = new AgendaAdapter(context, R.layout.agenda_item);
+        mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mStringBuilder = new StringBuilder(50);
+        mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
     }
 
     public int getCount() {
@@ -72,7 +84,7 @@
         if (mRowInfo != null) {
             RowInfo row = mRowInfo.get(position);
             if (row.mType == TYPE_DAY) {
-                return position;
+                return -position;
             } else {
                 return mAgendaAdapter.getItemId(row.mData);
             }
@@ -91,10 +103,6 @@
                 mRowInfo.get(position).mType : TYPE_DAY;
     }
 
-    private static class ViewHolder {
-        TextView dateView;
-    }
-
     public View getView(int position, View convertView, ViewGroup parent) {
         if ((mRowInfo == null) || (position > mRowInfo.size())) {
             // If we have no row info, mAgendaAdapter returns the view.
@@ -103,38 +111,59 @@
 
         RowInfo row = mRowInfo.get(position);
         if (row.mType == TYPE_DAY) {
-            ViewHolder holder;
-            View agendaDayView;
-            if ((convertView == null) || (convertView.getTag() == null)) {
+            ViewHolder holder = null;
+            View agendaDayView = null;
+            if ((convertView != null) && (convertView.getTag() != null)) {
+                // Listview may get confused and pass in a different type of
+                // view since we keep shifting data around. Not a big problem.
+                Object tag = convertView.getTag();
+                if (tag instanceof ViewHolder) {
+                    agendaDayView = convertView;
+                    holder = (ViewHolder) tag;
+                }
+            }
+
+            if (holder == null) {
                 // Create a new AgendaView with a ViewHolder for fast access to
                 // views w/o calling findViewById()
                 holder = new ViewHolder();
                 agendaDayView = mInflater.inflate(R.layout.agenda_day, parent, false);
                 holder.dateView = (TextView) agendaDayView.findViewById(R.id.date);
                 agendaDayView.setTag(holder);
-            } else {
-                agendaDayView = convertView;
-                holder = (ViewHolder) convertView.getTag();
             }
 
             // Re-use the member variable "mTime" which is set to the local timezone.
-            Time date = mTime;
+            Time date = mTmpTime;
             long millis = date.setJulianDay(row.mData);
             int flags = DateUtils.FORMAT_SHOW_YEAR
                     | DateUtils.FORMAT_SHOW_DATE;
-            
+
+            mStringBuilder.setLength(0);
+            String dateViewText;
             if (row.mData == mTodayJulianDay) {
-                String dayText = mContext.getResources().getText(R.string.agenda_today) + ", ";
-                holder.dateView.setText(dayText + DateUtils.formatDateTime(mContext, millis, flags));
+                dateViewText = mContext.getString(R.string.agenda_today, DateUtils.formatDateRange(
+                        mContext, mFormatter, millis, millis, flags).toString());
             } else {
                 flags |= DateUtils.FORMAT_SHOW_WEEKDAY;
-                holder.dateView.setText(DateUtils.formatDateTime(mContext, millis, flags));
+                dateViewText = DateUtils.formatDateRange(mContext, mFormatter, millis, millis,
+                        flags).toString();
             }
 
+            if (AgendaWindowAdapter.BASICLOG) {
+                dateViewText += " P:" + position;
+            }
+            holder.dateView.setText(dateViewText);
 
             return agendaDayView;
         } else if (row.mType == TYPE_MEETING) {
-            return mAgendaAdapter.getView(row.mData, convertView, parent);
+            View x = mAgendaAdapter.getView(row.mData, convertView, parent);
+            TextView y = ((AgendaAdapter.ViewHolder) x.getTag()).title;
+            if (AgendaWindowAdapter.BASICLOG) {
+                y.setText(y.getText() + " P:" + position);
+            } else {
+                y.setText(y.getText());
+            }
+            return x;
         } else {
             // Error
             throw new IllegalStateException("Unknown event type:" + row.mType);
@@ -145,7 +174,13 @@
         mRowInfo = null;
     }
 
-    public void calculateDays(Cursor cursor) {
+    public void changeCursor(DayAdapterInfo info) {
+        calculateDays(info);
+        mAgendaAdapter.changeCursor(info.cursor);
+    }
+
+    public void calculateDays(DayAdapterInfo dayAdapterInfo) {
+        Cursor cursor = dayAdapterInfo.cursor;
         ArrayList<RowInfo> rowInfo = new ArrayList<RowInfo>();
         int prevStartDay = -1;
         Time time = new Time();
@@ -154,8 +189,11 @@
         mTodayJulianDay = Time.getJulianDay(now, time.gmtoff);
         LinkedList<MultipleDayInfo> multipleDayList = new LinkedList<MultipleDayInfo>();
         for (int position = 0; cursor.moveToNext(); position++) {
-            boolean allDay = cursor.getInt(AgendaActivity.INDEX_ALL_DAY) != 0;
-            int startDay = cursor.getInt(AgendaActivity.INDEX_START_DAY);
+            boolean allDay = cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
+            int startDay = cursor.getInt(AgendaWindowAdapter.INDEX_START_DAY);
+
+            // Skip over the days outside of the adapter's range
+            startDay = Math.max(startDay, dayAdapterInfo.start);
 
             if (startDay != prevStartDay) {
                 // Check if we skipped over any empty days
@@ -202,7 +240,10 @@
 
             // If this event spans multiple days, then add it to the multipleDay
             // list.
-            int endDay = cursor.getInt(AgendaActivity.INDEX_END_DAY);
+            int endDay = cursor.getInt(AgendaWindowAdapter.INDEX_END_DAY);
+
+            // Skip over the days outside of the adapter's range
+            endDay = Math.min(endDay, dayAdapterInfo.end);
             if (endDay > startDay) {
                 multipleDayList.add(new MultipleDayInfo(position, endDay));
             }
@@ -211,16 +252,8 @@
         // There are no more cursor events but we might still have multiple-day
         // events left.  So create day headers and events for those.
         if (prevStartDay > 0) {
-            // Get the Julian day for the last day of this month.  To do that,
-            // we set the date to one less than the first day of the next month,
-            // and then normalize.
-            time.setJulianDay(prevStartDay);
-            time.month += 1;
-            time.monthDay = 0;  // monthDay starts with 1, so this is the previous day
-            long millis = time.normalize(true /* ignore isDst */);
-            int lastDayOfMonth = Time.getJulianDay(millis, time.gmtoff);
-
-            for (int currentDay = prevStartDay + 1; currentDay <= lastDayOfMonth; currentDay++) {
+            for (int currentDay = prevStartDay + 1; currentDay <= dayAdapterInfo.end;
+                    currentDay++) {
                 boolean dayHeaderAdded = false;
                 Iterator<MultipleDayInfo> iter = multipleDayList.iterator();
                 while (iter.hasNext()) {
@@ -342,9 +375,17 @@
             RowInfo row = mRowInfo.get(listPos);
             if (row.mType == TYPE_MEETING) {
                 return row.mData;
+            } else {
+                int nextPos = listPos + 1;
+                if (nextPos < mRowInfo.size()) {
+                    nextPos = getCursorPosition(nextPos);
+                    if (nextPos >= 0) {
+                        return -nextPos;
+                    }
+                }
             }
         }
-        return listPos;
+        return Integer.MIN_VALUE;
     }
 
     @Override
@@ -361,4 +402,3 @@
         return true;
     }
 }
-
diff --git a/src/com/android/calendar/AgendaListView.java b/src/com/android/calendar/AgendaListView.java
new file mode 100644
index 0000000..f5e63b4
--- /dev/null
+++ b/src/com/android/calendar/AgendaListView.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.calendar;
+
+import android.content.ContentUris;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.provider.Calendar;
+import android.provider.Calendar.Events;
+import android.text.format.Time;
+import android.util.Log;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.AdapterView.OnItemClickListener;
+
+import com.android.calendar.AgendaAdapter.ViewHolder;
+import com.android.calendar.AgendaWindowAdapter.EventInfo;
+
+public class AgendaListView extends ListView implements OnItemClickListener {
+
+    private static final String TAG = "AgendaListView";
+    private static final boolean DEBUG = false;
+
+    private AgendaWindowAdapter mWindowAdapter;
+
+    private AgendaActivity mAgendaActivity;
+    private DeleteEventHelper mDeleteEventHelper;
+
+    public AgendaListView(AgendaActivity agendaActivity) {
+        super(agendaActivity, null);
+        mAgendaActivity = agendaActivity;
+        mContext = agendaActivity;
+
+        setOnItemClickListener(this);
+        setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+        setVerticalScrollBarEnabled(false);
+        mWindowAdapter = new AgendaWindowAdapter(agendaActivity, this);
+        setAdapter(mWindowAdapter);
+        mDeleteEventHelper =
+            new DeleteEventHelper(agendaActivity, false /* don't exit when done */);
+    }
+
+    @Override protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mWindowAdapter.close();
+    }
+
+    // Implementation of the interface OnItemClickListener
+    public void onItemClick(AdapterView<?> a, View v, int position, long id) {
+        if (id != -1) {
+            // Switch to the EventInfo view
+            EventInfo event = mWindowAdapter.getEventByPosition(position);
+            if (event != null) {
+                Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, event.id);
+                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+                intent.putExtra(Calendar.EVENT_BEGIN_TIME, event.begin);
+                intent.putExtra(Calendar.EVENT_END_TIME, event.end);
+                mAgendaActivity.startActivity(intent);
+            }
+        }
+    }
+
+    public void goTo(Time time, boolean forced) {
+        mWindowAdapter.refresh(time, forced);
+    }
+
+    public void refresh(boolean forced) {
+        Time time = new Time();
+        long goToTime = getFirstVisibleTime();
+        if (goToTime <= 0) {
+            goToTime = System.currentTimeMillis();
+        }
+        time.set(goToTime);
+        mWindowAdapter.refresh(time, forced);
+    }
+
+    public void deleteSelectedEvent() {
+        int position = getSelectedItemPosition();
+        EventInfo event = mWindowAdapter.getEventByPosition(position);
+        if (event != null) {
+            mDeleteEventHelper.delete(event.begin, event.end, event.id, -1);
+        }
+    }
+
+    @Override
+    public int getFirstVisiblePosition() {
+        // TODO File bug!
+        // getFirstVisiblePosition doesn't always return the first visible
+        // item. Sometimes, it is above the visible one.
+        // instead. I loop through the viewgroup children and find the first
+        // visible one. BTW, getFirstVisiblePosition() == getChildAt(0). I
+        // am not looping through the entire list.
+       View v = getFirstVisibleView();
+       if (v != null) {
+           if (DEBUG) {
+               Log.v(TAG, "getFirstVisiblePosition: " + AgendaWindowAdapter.getViewTitle(v));
+           }
+           return getPositionForView(v);
+       }
+       return -1;
+    }
+
+    public View getFirstVisibleView() {
+        Rect r = new Rect();
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; ++i) {
+            View listItem = getChildAt(i);
+            listItem.getLocalVisibleRect(r);
+            if (r.top >= 0) { // if visible
+                return listItem;
+            }
+        }
+        return null;
+    }
+
+    public long getSelectedTime() {
+        int position = getSelectedItemPosition();
+        if (position >= 0) {
+            EventInfo event = mWindowAdapter.getEventByPosition(position);
+            if (event != null) {
+                return event.begin;
+            }
+        }
+        return getFirstVisibleTime();
+    }
+
+    public long getFirstVisibleTime() {
+        int position = getFirstVisiblePosition();
+        if (DEBUG) {
+            Log.v(TAG, "getFirstVisiblePosition = " + position);
+        }
+
+        EventInfo event = mWindowAdapter.getEventByPosition(position);
+        if (event != null) {
+            return event.begin;
+        }
+        return 0;
+    }
+
+    // Move the currently selected or visible focus down by offset amount.
+    // offset could be negative.
+    public void shiftSelection(int offset) {
+        shiftPosition(offset);
+        int position = getSelectedItemPosition();
+        if (position != INVALID_POSITION) {
+            setSelectionFromTop(position + offset, 0);
+        }
+    }
+
+    private void shiftPosition(int offset) {
+        if (DEBUG) {
+            Log.v(TAG, "Shifting position "+ offset);
+        }
+
+        View firstVisibleItem = getFirstVisibleView();
+
+        if (firstVisibleItem != null) {
+            Rect r = new Rect();
+            firstVisibleItem.getLocalVisibleRect(r);
+            // if r.top is < 0, getChildAt(0) and getFirstVisiblePosition() is
+            // returning an item above the first visible item.
+            int position = getPositionForView(firstVisibleItem);
+            setSelectionFromTop(position + offset, r.top > 0 ? -r.top : r.top);
+            if (DEBUG) {
+                if (firstVisibleItem.getTag() instanceof AgendaAdapter.ViewHolder) {
+                    ViewHolder viewHolder = (AgendaAdapter.ViewHolder)firstVisibleItem.getTag();
+                    Log.v(TAG, "Shifting from " + position + " by " + offset + ". Title "
+                            + viewHolder.title.getText());
+                } else if (firstVisibleItem.getTag() instanceof AgendaByDayAdapter.ViewHolder) {
+                    AgendaByDayAdapter.ViewHolder viewHolder =
+                        (AgendaByDayAdapter.ViewHolder)firstVisibleItem.getTag();
+                    Log.v(TAG, "Shifting from " + position + " by " + offset + ". Date  "
+                            + viewHolder.dateView.getText());
+                } else if (firstVisibleItem instanceof TextView) {
+                    Log.v(TAG, "Shifting: Looking at header here. " + getSelectedItemPosition());
+                }
+            }
+        } else if (getSelectedItemPosition() >= 0) {
+            if (DEBUG) {
+                Log.v(TAG, "Shifting selection from " + getSelectedItemPosition() + " by " + offset);
+            }
+            setSelection(getSelectedItemPosition() + offset);
+        }
+    }
+
+    public void setHideDeclinedEvents(boolean hideDeclined) {
+        mWindowAdapter.setHideDeclinedEvents(hideDeclined);
+    }
+
+    public void onResume() {
+        mWindowAdapter.notifyDataSetChanged();
+    }
+    public void onPause() {
+        mWindowAdapter.notifyDataSetInvalidated();
+    }
+}
diff --git a/src/com/android/calendar/AgendaWindowAdapter.java b/src/com/android/calendar/AgendaWindowAdapter.java
new file mode 100644
index 0000000..9d4fb46
--- /dev/null
+++ b/src/com/android/calendar/AgendaWindowAdapter.java
@@ -0,0 +1,886 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+package com.android.calendar;
+
+import android.content.AsyncQueryHandler;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.Calendar.Attendees;
+import android.provider.Calendar.Calendars;
+import android.provider.Calendar.Instances;
+import android.text.format.DateUtils;
+import android.text.format.Time;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import java.util.Formatter;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Locale;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/*
+Bugs Bugs Bugs:
+- At rotation and launch time, the initial position is not set properly. This code is calling
+ listview.setSelection() in 2 rapid secessions but it dropped or didn't process the first one.
+- Scroll using trackball isn't repositioning properly after a new adapter is added.
+- Track ball clicks at the header/footer doesn't work.
+- Potential ping pong effect if the prefetch window is big and data is limited
+- Add index in calendar provider
+
+ToDo ToDo ToDo:
+Get design of header and footer from designer
+
+Make scrolling smoother.
+Test for correctness
+Loading speed
+Check for leaks and excessive allocations
+ */
+
+public class AgendaWindowAdapter extends BaseAdapter {
+
+    static final boolean BASICLOG = false;
+    static final boolean DEBUGLOG = false;
+    private static String TAG = "AgendaWindowAdapter";
+
+    private static final String AGENDA_SORT_ORDER = "startDay ASC, begin ASC, title ASC";
+    public static final int INDEX_TITLE = 1;
+    public static final int INDEX_EVENT_LOCATION = 2;
+    public static final int INDEX_ALL_DAY = 3;
+    public static final int INDEX_HAS_ALARM = 4;
+    public static final int INDEX_COLOR = 5;
+    public static final int INDEX_RRULE = 6;
+    public static final int INDEX_BEGIN = 7;
+    public static final int INDEX_END = 8;
+    public static final int INDEX_EVENT_ID = 9;
+    public static final int INDEX_START_DAY = 10;
+    public static final int INDEX_END_DAY = 11;
+    public static final int INDEX_SELF_ATTENDEE_STATUS = 12;
+
+    private static final String[] PROJECTION = new String[] {
+            Instances._ID, // 0
+            Instances.TITLE, // 1
+            Instances.EVENT_LOCATION, // 2
+            Instances.ALL_DAY, // 3
+            Instances.HAS_ALARM, // 4
+            Instances.COLOR, // 5
+            Instances.RRULE, // 6
+            Instances.BEGIN, // 7
+            Instances.END, // 8
+            Instances.EVENT_ID, // 9
+            Instances.START_DAY, // 10 Julian start day
+            Instances.END_DAY, // 11 Julian end day
+            Instances.SELF_ATTENDEE_STATUS, // 12
+    };
+
+    // Listview may have a bug where the index/position is not consistent when there's a header.
+    // TODO Need to look into this.
+    private static final int OFF_BY_ONE_BUG = 1;
+
+    private static final int MAX_NUM_OF_ADAPTERS = 5;
+
+    private static final int IDEAL_NUM_OF_EVENTS = 50;
+
+    private static final int MIN_QUERY_DURATION = 7; // days
+
+    private static final int MAX_QUERY_DURATION = 60; // days
+
+    private static final int PREFETCH_BOUNDARY = 1;
+
+    // Times to auto-expand/retry query after getting no data
+    private static final int RETRIES_ON_NO_DATA = 0;
+
+    private Context mContext;
+
+    private QueryHandler mQueryHandler;
+
+    private AgendaListView mAgendaListView;
+
+    private int mRowCount; // The sum of the rows in all the adapters
+
+    private int mEmptyCursorCount;
+
+    private DayAdapterInfo mLastUsedInfo; // Cached value of the last used adapter.
+
+    private LinkedList<DayAdapterInfo> mAdapterInfos = new LinkedList<DayAdapterInfo>();
+
+    private ConcurrentLinkedQueue<QuerySpec> mQueryQueue = new ConcurrentLinkedQueue<QuerySpec>();
+
+    private TextView mHeaderView;
+
+    private TextView mFooterView;
+
+    private boolean mDoneSettingUpHeaderFooter = false;
+
+    /*
+     * When the user scrolled to the top, a query will be made for older events
+     * and this will be incremented. Don't make more requests if
+     * mOlderRequests > mOlderRequestsProcessed.
+     */
+    private int mOlderRequests;
+
+    // Number of "older" query that has been processed.
+    private int mOlderRequestsProcessed;
+
+    /*
+     * When the user scrolled to the bottom, a query will be made for newer
+     * events and this will be incremented. Don't make more requests if
+     * mNewerRequests > mNewerRequestsProcessed.
+     */
+    private int mNewerRequests;
+
+    // Number of "newer" query that has been processed.
+    private int mNewerRequestsProcessed;
+
+    // Note: Formatter is not thread safe. Fine for now as it is only used by the main thread.
+    private Formatter mFormatter;
+    private StringBuilder mStringBuilder;
+
+    private boolean mShuttingDown;
+    private boolean mHideDeclined;
+
+    // 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
+    private static final int QUERY_TYPE_CLEAN = 2; // Delete everything and query around a date
+
+    private static class QuerySpec {
+        long queryStartMillis;
+
+        Time goToTime;
+
+        int start;
+
+        int end;
+
+        int queryType;
+
+        public QuerySpec(int queryType) {
+            this.queryType = queryType;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + end;
+            result = prime * result + (int) (queryStartMillis ^ (queryStartMillis >>> 32));
+            result = prime * result + queryType;
+            result = prime * result + start;
+            if (goToTime != null) {
+                long goToTimeMillis = goToTime.toMillis(false);
+                result = prime * result + (int) (goToTimeMillis ^ (goToTimeMillis >>> 32));
+            }
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) return true;
+            if (obj == null) return false;
+            if (getClass() != obj.getClass()) return false;
+            QuerySpec other = (QuerySpec) obj;
+            if (end != other.end || queryStartMillis != other.queryStartMillis
+                    || queryType != other.queryType || start != other.start) {
+                return false;
+            }
+            if (goToTime != null) {
+                if (goToTime.toMillis(false) != other.goToTime.toMillis(false)) {
+                    return false;
+                }
+            } else {
+                if (other.goToTime != null) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    static class EventInfo {
+        long begin;
+
+        long end;
+
+        long id;
+    }
+
+    static class DayAdapterInfo {
+        Cursor cursor;
+
+        AgendaByDayAdapter dayAdapter;
+
+        int start; // start day of the cursor's coverage
+
+        int end; // end day of the cursor's coverage
+
+        int offset; // offset in position in the list view
+
+        int size; // dayAdapter.getCount()
+
+        public DayAdapterInfo(Context context) {
+            dayAdapter = new AgendaByDayAdapter(context);
+        }
+
+        @Override
+        public String toString() {
+            Time time = new Time();
+            StringBuilder sb = new StringBuilder();
+            time.setJulianDay(start);
+            time.normalize(false);
+            sb.append("Start:").append(time.toString());
+            time.setJulianDay(end);
+            time.normalize(false);
+            sb.append(" End:").append(time.toString());
+            sb.append(" Offset:").append(offset);
+            sb.append(" Size:").append(size);
+            return sb.toString();
+        }
+    }
+
+    public AgendaWindowAdapter(AgendaActivity agendaActivity,
+            AgendaListView agendaListView) {
+        mContext = agendaActivity;
+        mAgendaListView = agendaListView;
+        mQueryHandler = new QueryHandler(agendaActivity.getContentResolver());
+
+        mStringBuilder = new StringBuilder(50);
+        mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
+
+        LayoutInflater inflater = (LayoutInflater) agendaActivity
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mHeaderView = (TextView)inflater.inflate(R.layout.agenda_header_footer, null);
+        mFooterView = (TextView)inflater.inflate(R.layout.agenda_header_footer, null);
+        mHeaderView.setText(R.string.loading);
+        mAgendaListView.addHeaderView(mHeaderView);
+    }
+
+    // Method in Adapter
+    @Override
+    public int getViewTypeCount() {
+        return AgendaByDayAdapter.TYPE_LAST;
+    }
+
+    // Method in BaseAdapter
+    @Override
+    public boolean areAllItemsEnabled() {
+        return false;
+    }
+
+    // Method in Adapter
+    @Override
+    public int getItemViewType(int position) {
+        DayAdapterInfo info = getAdapterInfoByPosition(position);
+        if (info != null) {
+            return info.dayAdapter.getItemViewType(position - info.offset);
+        } else {
+            return -1;
+        }
+    }
+
+    // Method in BaseAdapter
+    @Override
+    public boolean isEnabled(int position) {
+        DayAdapterInfo info = getAdapterInfoByPosition(position);
+        if (info != null) {
+            return info.dayAdapter.isEnabled(position - info.offset);
+        } else {
+            return false;
+        }
+    }
+
+    // Abstract Method in BaseAdapter
+    public int getCount() {
+        return mRowCount;
+    }
+
+    // Abstract Method in BaseAdapter
+    public Object getItem(int position) {
+        DayAdapterInfo info = getAdapterInfoByPosition(position);
+        if (info != null) {
+            return info.dayAdapter.getItem(position - info.offset);
+        } else {
+            return null;
+        }
+    }
+
+    // Method in BaseAdapter
+    @Override
+    public boolean hasStableIds() {
+        return true;
+    }
+
+    // Abstract Method in BaseAdapter
+    public long getItemId(int position) {
+        DayAdapterInfo info = getAdapterInfoByPosition(position);
+        if (info != null) {
+            return ((position - info.offset) << 20) + info.start ;
+        } else {
+            return -1;
+        }
+    }
+
+    // Abstract Method in BaseAdapter
+    public View getView(int position, View convertView, ViewGroup parent) {
+        if (position >= (mRowCount - PREFETCH_BOUNDARY)
+                && mNewerRequests <= mNewerRequestsProcessed) {
+            if (DEBUGLOG) Log.e(TAG, "queryForNewerEvents: ");
+            mNewerRequests++;
+            queueQuery(new QuerySpec(QUERY_TYPE_NEWER));
+        }
+
+        if (position < PREFETCH_BOUNDARY
+                && mOlderRequests <= mOlderRequestsProcessed) {
+            if (DEBUGLOG) Log.e(TAG, "queryForOlderEvents: ");
+            mOlderRequests++;
+            queueQuery(new QuerySpec(QUERY_TYPE_OLDER));
+        }
+
+        View v;
+        DayAdapterInfo info = getAdapterInfoByPosition(position);
+        if (info != null) {
+            v = info.dayAdapter.getView(position - info.offset, convertView,
+                    parent);
+        } else {
+            //TODO
+            Log.e(TAG, "BUG: getAdapterInfoByPosition returned null!!! " + position);
+            TextView tv = new TextView(mContext);
+            tv.setText("Bug! " + position);
+            v = tv;
+        }
+
+        if (DEBUGLOG) {
+            Log.e(TAG, "getView " + position + " = " + getViewTitle(v));
+        }
+        return v;
+    }
+
+    private int findDayPositionNearestTime(Time time) {
+        if (DEBUGLOG) Log.e(TAG, "findDayPositionNearestTime " + time);
+
+        DayAdapterInfo info = getAdapterInfoByTime(time);
+        if (info != null) {
+            return info.offset + info.dayAdapter.findDayPositionNearestTime(time);
+        } else {
+            return -1;
+        }
+    }
+
+    private DayAdapterInfo getAdapterInfoByPosition(int position) {
+        synchronized (mAdapterInfos) {
+            if (mLastUsedInfo != null && mLastUsedInfo.offset <= position
+                    && position < (mLastUsedInfo.offset + mLastUsedInfo.size)) {
+                return mLastUsedInfo;
+            }
+            for (DayAdapterInfo info : mAdapterInfos) {
+                if (info.offset <= position
+                        && position < (info.offset + info.size)) {
+                    mLastUsedInfo = info;
+                    return info;
+                }
+            }
+        }
+        return null;
+    }
+
+    private DayAdapterInfo getAdapterInfoByTime(Time time) {
+        if (DEBUGLOG) Log.e(TAG, "getAdapterInfoByTime " + time.toString());
+
+        Time tmpTime = new Time(time);
+        long timeInMillis = tmpTime.normalize(true);
+        int day = Time.getJulianDay(timeInMillis, tmpTime.gmtoff);
+        synchronized (mAdapterInfos) {
+            for (DayAdapterInfo info : mAdapterInfos) {
+                if (info.start <= day && day < info.end) {
+                    return info;
+                }
+            }
+        }
+        return null;
+    }
+
+    public EventInfo getEventByPosition(int position) {
+        if (DEBUGLOG) Log.e(TAG, "getEventByPosition " + position);
+
+        EventInfo event = new EventInfo();
+        position -= OFF_BY_ONE_BUG;
+        DayAdapterInfo info = getAdapterInfoByPosition(position);
+        if (info == null) {
+            return null;
+        }
+
+        position = info.dayAdapter.getCursorPosition(position - info.offset);
+        if (position == Integer.MIN_VALUE) {
+            return null;
+        }
+
+        boolean isDayHeader = false;
+        if (position < 0) {
+            position = -position;
+            isDayHeader = true;
+        }
+
+        if (position < info.cursor.getCount()) {
+            info.cursor.moveToPosition(position);
+            event.begin = info.cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
+            boolean allDay = info.cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
+
+            if (allDay) { // UTC
+                Time time = new Time();
+                time.setJulianDay(Time.getJulianDay(event.begin, 0));
+                event.begin = time.toMillis(false /* use isDst */);
+            } else if (isDayHeader) { // Trim to midnight.
+                Time time = new Time();
+                time.set(event.begin);
+                time.hour = 0;
+                time.minute = 0;
+                time.second = 0;
+                event.begin = time.toMillis(false /* use isDst */);
+            }
+
+            if (!isDayHeader) {
+                event.end = info.cursor.getLong(AgendaWindowAdapter.INDEX_END);
+                event.id = info.cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID);
+            }
+            return event;
+        }
+        return null;
+    }
+
+    public void refresh(Time goToTime, boolean forced) {
+        if (DEBUGLOG) {
+            Log.e(TAG, "refresh " + goToTime.toString() + (forced ? " forced" : " not forced"));
+        }
+        
+        int startDay = Time.getJulianDay(goToTime.toMillis(false), goToTime.gmtoff);
+
+        if (!forced && isInRange(startDay, startDay)) {
+            // No need to requery
+            mAgendaListView.setSelection(findDayPositionNearestTime(goToTime) + OFF_BY_ONE_BUG);
+            return;
+        }
+
+        // Query for a total of MIN_QUERY_DURATION days
+        int endDay = startDay + MIN_QUERY_DURATION;
+
+        queueQuery(startDay, endDay, goToTime, QUERY_TYPE_CLEAN);
+    }
+
+    public void close() {
+        mShuttingDown = true;
+        pruneAdapterInfo(QUERY_TYPE_CLEAN);
+        if (mQueryHandler != null) {
+            mQueryHandler.cancelOperation(0);
+        }
+    }
+
+    private DayAdapterInfo pruneAdapterInfo(int queryType) {
+        synchronized (mAdapterInfos) {
+            DayAdapterInfo recycleMe = null;
+            if (!mAdapterInfos.isEmpty()) {
+                if (mAdapterInfos.size() >= MAX_NUM_OF_ADAPTERS) {
+                    if (queryType == QUERY_TYPE_NEWER) {
+                        recycleMe = mAdapterInfos.removeFirst();
+                    } else if (queryType == QUERY_TYPE_OLDER) {
+                        recycleMe = mAdapterInfos.removeLast();
+                        // Keep the size only if the oldest items are removed.
+                        recycleMe.size = 0;
+                    }
+                    if (recycleMe != null) {
+                        if (recycleMe.cursor != null) {
+                            recycleMe.cursor.close();
+                        }
+                        return recycleMe;
+                    }
+                }
+
+                if (mRowCount == 0 || queryType == QUERY_TYPE_CLEAN) {
+                    mRowCount = 0;
+                    int deletedRows = 0;
+                    DayAdapterInfo info;
+                    do {
+                        info = mAdapterInfos.poll();
+                        if (info != null) {
+                            info.cursor.close();
+                            deletedRows += info.size;
+                            recycleMe = info;
+                        }
+                    } while (info != null);
+
+                    if (recycleMe != null) {
+                        recycleMe.cursor = null;
+                        recycleMe.size = deletedRows;
+                    }
+                }
+            }
+            return recycleMe;
+        }
+    }
+
+    private String buildQuerySelection() {
+        // Respect the preference to show/hide declined events
+
+        if (mHideDeclined) {
+            return Calendars.SELECTED + "=1 AND "
+                    + Instances.SELF_ATTENDEE_STATUS + "!="
+                    + Attendees.ATTENDEE_STATUS_DECLINED;
+        } else {
+            return Calendars.SELECTED + "=1";
+        }
+    }
+
+    private Uri buildQueryUri(int start, int end) {
+        StringBuilder path = new StringBuilder();
+        path.append(start);
+        path.append('/');
+        path.append(end);
+        Uri uri = Uri.withAppendedPath(Instances.CONTENT_BY_DAY_URI, path.toString());
+        return uri;
+    }
+
+    private boolean isInRange(int start, int end) {
+        synchronized (mAdapterInfos) {
+            if (mAdapterInfos.isEmpty()) {
+                return false;
+            }
+            return mAdapterInfos.getFirst().start <= start && end <= mAdapterInfos.getLast().end;
+        }
+    }
+
+    private int calculateQueryDuration(int start, int end) {
+        int queryDuration = MAX_QUERY_DURATION;
+        if (mRowCount != 0) {
+            queryDuration = IDEAL_NUM_OF_EVENTS * (end - start + 1) / mRowCount;
+        }
+
+        if (queryDuration > MAX_QUERY_DURATION) {
+            queryDuration = MAX_QUERY_DURATION;
+        } else if (queryDuration < MIN_QUERY_DURATION) {
+            queryDuration = MIN_QUERY_DURATION;
+        }
+
+        return queryDuration;
+    }
+
+    private boolean queueQuery(int start, int end, Time goToTime, int queryType) {
+        QuerySpec queryData = new QuerySpec(queryType);
+        queryData.goToTime = goToTime;
+        queryData.start = start;
+        queryData.end = end;
+        return queueQuery(queryData);
+    }
+
+    private boolean queueQuery(QuerySpec queryData) {
+        Boolean queuedQuery;
+        synchronized (mQueryQueue) {
+            queuedQuery = false;
+            Boolean doQueryNow = mQueryQueue.isEmpty();
+            mQueryQueue.add(queryData);
+            queuedQuery = true;
+            if (doQueryNow) {
+                doQuery(queryData);
+            }
+        }
+        return queuedQuery;
+    }
+
+    private void doQuery(QuerySpec queryData) {
+        if (!mAdapterInfos.isEmpty()) {
+            int start = mAdapterInfos.getFirst().start;
+            int end = mAdapterInfos.getLast().end;
+            int queryDuration = calculateQueryDuration(start, end);
+            switch(queryData.queryType) {
+                case QUERY_TYPE_OLDER:
+                    queryData.end = start - 1;
+                    queryData.start = queryData.end - queryDuration;
+                    break;
+                case QUERY_TYPE_NEWER:
+                    queryData.start = end + 1;
+                    queryData.end = queryData.start + queryDuration;
+                    break;
+            }
+        }
+
+        if (BASICLOG) {
+            Time time = new Time();
+            time.setJulianDay(queryData.start);
+            Time time2 = new Time();
+            time2.setJulianDay(queryData.end);
+            Log.v(TAG, "startQuery: " + time.toString() + " to "
+                    + time2.toString() + " then go to " + queryData.goToTime);
+        }
+
+        mQueryHandler.cancelOperation(0);
+        if (BASICLOG) queryData.queryStartMillis = System.nanoTime();
+        mQueryHandler.startQuery(0, queryData, buildQueryUri(
+                queryData.start, queryData.end), PROJECTION,
+                buildQuerySelection(), null, AGENDA_SORT_ORDER);
+    }
+
+    private String formatDateString(int julianDay) {
+        Time time = new Time();
+        time.setJulianDay(julianDay);
+        long millis = time.toMillis(false);
+        mStringBuilder.setLength(0);
+        return DateUtils.formatDateRange(mContext, mFormatter, millis, millis,
+                DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE
+                        | DateUtils.FORMAT_ABBREV_MONTH).toString();
+    }
+
+    private void updateHeaderFooter(final int start, final int end) {
+        mHeaderView.setText(mContext.getString(R.string.show_older_events,
+                formatDateString(start)));
+        mFooterView.setText(mContext.getString(R.string.show_newer_events,
+                formatDateString(end)));
+    }
+
+    private class QueryHandler extends AsyncQueryHandler {
+
+        public QueryHandler(ContentResolver cr) {
+            super(cr);
+        }
+
+        @Override
+        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
+            QuerySpec data = (QuerySpec)cookie;
+            if (BASICLOG) {
+                long queryEndMillis = System.nanoTime();
+                Log.e(TAG, "Query time(ms): "
+                        + (queryEndMillis - data.queryStartMillis) / 1000000
+                        + " Count: " + cursor.getCount());
+            }
+
+            if (mShuttingDown) {
+                cursor.close();
+                return;
+            }
+
+            // Notify Listview of changes and update position
+            int cursorSize = cursor.getCount();
+            if (cursorSize > 0 || mAdapterInfos.isEmpty()) {
+                final int listPositionOffset = processNewCursor(data, cursor);
+                if (data.goToTime == null) { // Typical Scrolling type query
+                    notifyDataSetChanged();
+                    if (listPositionOffset != 0) {
+                        mAgendaListView.shiftSelection(listPositionOffset);
+                    }
+                } else { // refresh() called. Go to the designated position
+                    final Time goToTime = data.goToTime;
+                    notifyDataSetChanged();
+                    int newPosition = findDayPositionNearestTime(goToTime);
+                    if (newPosition >= 0) {
+                        mAgendaListView.setSelection(newPosition + OFF_BY_ONE_BUG);
+                    }
+                    if (DEBUGLOG)
+                        Log.e(TAG, "Setting listview to " +
+                        		"findDayPositionNearestTime: " + (newPosition + OFF_BY_ONE_BUG));
+                }
+            } else {
+                cursor.close();
+            }
+
+            // Update header and footer
+            if (!mDoneSettingUpHeaderFooter) {
+                OnClickListener headerFooterOnClickListener = new OnClickListener() {
+                    public void onClick(View v) {
+                        if (v == mHeaderView) {
+                            queueQuery(new QuerySpec(QUERY_TYPE_OLDER));
+                        } else {
+                            queueQuery(new QuerySpec(QUERY_TYPE_NEWER));
+                        }
+                    }};
+                mHeaderView.setOnClickListener(headerFooterOnClickListener);
+                mFooterView.setOnClickListener(headerFooterOnClickListener);
+                mAgendaListView.addFooterView(mFooterView);
+                mDoneSettingUpHeaderFooter = true;
+            }
+            synchronized (mQueryQueue) {
+                int totalAgendaRangeStart = -1;
+                int totalAgendaRangeEnd = -1;
+
+                if (cursorSize != 0) {
+                    // Remove the query that just completed
+                    QuerySpec x = mQueryQueue.poll();
+                    if (BASICLOG && !x.equals(data)) {
+                        Log.e(TAG, "onQueryComplete - cookie != head of queue");
+                    }
+                    mEmptyCursorCount = 0;
+                    if (data.queryType == QUERY_TYPE_NEWER) {
+                        mNewerRequestsProcessed++;
+                    } else if (data.queryType == QUERY_TYPE_OLDER) {
+                        mOlderRequestsProcessed++;
+                    }
+
+                    totalAgendaRangeStart = mAdapterInfos.getFirst().start;
+                    totalAgendaRangeEnd = mAdapterInfos.getLast().end;
+                } else { // CursorSize == 0
+                    QuerySpec querySpec = mQueryQueue.peek();
+
+                    // Update Adapter Info with new start and end date range
+                    if (!mAdapterInfos.isEmpty()) {
+                        DayAdapterInfo first = mAdapterInfos.getFirst();
+                        DayAdapterInfo last = mAdapterInfos.getLast();
+
+                        if (first.start - 1 <= querySpec.end && querySpec.start < first.start) {
+                            first.start = querySpec.start;
+                        }
+
+                        if (querySpec.start <= last.end + 1 && last.end < querySpec.end) {
+                            last.end = querySpec.end;
+                        }
+
+                        totalAgendaRangeStart = first.start;
+                        totalAgendaRangeEnd = last.end;
+                    } else {
+                        totalAgendaRangeStart = querySpec.start;
+                        totalAgendaRangeEnd = querySpec.end;
+                    }
+
+                    // Update query specification with expanded search range
+                    // and maybe rerun query
+                    switch (querySpec.queryType) {
+                        case QUERY_TYPE_OLDER:
+                            totalAgendaRangeStart = querySpec.start;
+                            querySpec.start -= MAX_QUERY_DURATION;
+                            break;
+                        case QUERY_TYPE_NEWER:
+                            totalAgendaRangeEnd = querySpec.end;
+                            querySpec.end += MAX_QUERY_DURATION;
+                            break;
+                        case QUERY_TYPE_CLEAN:
+                            totalAgendaRangeStart = querySpec.start;
+                            totalAgendaRangeEnd = querySpec.end;
+                            querySpec.start -= MAX_QUERY_DURATION / 2;
+                            querySpec.end += MAX_QUERY_DURATION / 2;
+                            break;
+                    }
+
+                    if (++mEmptyCursorCount > RETRIES_ON_NO_DATA) {
+                        // Nothing in the cursor again. Dropping query
+                        mQueryQueue.poll();
+                    }
+                }
+
+                updateHeaderFooter(totalAgendaRangeStart, totalAgendaRangeEnd);
+
+                // Fire off the next query if any
+                Iterator<QuerySpec> it = mQueryQueue.iterator();
+                while (it.hasNext()) {
+                    QuerySpec queryData = it.next();
+                    if (!isInRange(queryData.start, queryData.end)) {
+                        // Query accepted
+                        if (DEBUGLOG) Log.e(TAG, "Query accepted. QueueSize:" + mQueryQueue.size());
+                        doQuery(queryData);
+                        break;
+                    } else {
+                        // Query rejected
+                        it.remove();
+                        if (DEBUGLOG) Log.e(TAG, "Query rejected. QueueSize:" + mQueryQueue.size());
+                    }
+                }
+            }
+            if (BASICLOG) {
+                for (DayAdapterInfo info3 : mAdapterInfos) {
+                    Log.e(TAG, "> " + info3.toString());
+                }
+            }
+        }
+
+        /*
+         * Update the adapter info array with a the new cursor. Close out old
+         * cursors as needed.
+         *
+         * @return number of rows removed from the beginning
+         */
+        private int processNewCursor(QuerySpec data, Cursor cursor) {
+            synchronized (mAdapterInfos) {
+                // Remove adapter info's from adapterInfos as needed
+                DayAdapterInfo info = pruneAdapterInfo(data.queryType);
+                int listPositionOffset = 0;
+                if (info == null) {
+                    info = new DayAdapterInfo(mContext);
+                } else {
+                    if (DEBUGLOG)
+                        Log.e(TAG, "processNewCursor listPositionOffsetA="
+                                + -info.size);
+                    listPositionOffset = -info.size;
+                }
+
+                // Setup adapter info
+                info.start = data.start;
+                info.end = data.end;
+                info.cursor = cursor;
+                info.dayAdapter.changeCursor(info);
+                info.size = info.dayAdapter.getCount();
+
+                // Insert into adapterInfos
+                if (mAdapterInfos.isEmpty()
+                        || data.end <= mAdapterInfos.getFirst().start) {
+                    mAdapterInfos.addFirst(info);
+                    listPositionOffset += info.size;
+                } else if (BASICLOG && data.start < mAdapterInfos.getLast().end) {
+                    mAdapterInfos.addLast(info);
+                    for (DayAdapterInfo info2 : mAdapterInfos) {
+                        Log.e("========== BUG ==", info2.toString());
+                    }
+                } else {
+                    mAdapterInfos.addLast(info);
+                }
+
+                // Update offsets in adapterInfos
+                mRowCount = 0;
+                for (DayAdapterInfo info3 : mAdapterInfos) {
+                    info3.offset = mRowCount;
+                    mRowCount += info3.size;
+                }
+                mLastUsedInfo = null;
+
+                return listPositionOffset;
+            }
+        }
+    }
+
+    static String getViewTitle(View x) {
+        String title = "";
+        if (x != null) {
+            Object yy = x.getTag();
+            if (yy instanceof AgendaAdapter.ViewHolder) {
+                TextView tv = ((AgendaAdapter.ViewHolder) yy).title;
+                if (tv != null) {
+                    title = (String) tv.getText();
+                }
+            } else if (yy != null) {
+                TextView dateView = ((AgendaByDayAdapter.ViewHolder) yy).dateView;
+                if (dateView != null) {
+                    title = (String) dateView.getText();
+                }
+            }
+        }
+        return title;
+    }
+
+    public void setHideDeclinedEvents(boolean hideDeclined) {
+        mHideDeclined = hideDeclined;
+    }
+}
diff --git a/src/com/android/calendar/AlertActivity.java b/src/com/android/calendar/AlertActivity.java
index dcf9186..2a041bf 100644
--- a/src/com/android/calendar/AlertActivity.java
+++ b/src/com/android/calendar/AlertActivity.java
@@ -219,7 +219,6 @@
         a.recycle();
 
         getWindow().setAttributes(lp);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
 
         mResolver = getContentResolver();
         mQueryHandler = new QueryHandler(mResolver);
diff --git a/src/com/android/calendar/AlertService.java b/src/com/android/calendar/AlertService.java
index 558a8f6..3719f6b 100644
--- a/src/com/android/calendar/AlertService.java
+++ b/src/com/android/calendar/AlertService.java
@@ -113,6 +113,11 @@
         }
 
         if (alertUri != null) {
+            if (!Calendar.AUTHORITY.equals(alertUri.getAuthority())) {
+                Log.w(TAG, "Invalid AUTHORITY uri: " + alertUri);
+                return;
+            }
+
             // Record the received time in the CalendarAlerts table.
             // This is useful for finding bugs that cause alarms to be
             // missed or delayed.
@@ -427,11 +432,14 @@
     }
 
     @Override
-    public void onStart(Intent intent, int startId) {
-        Message msg = mServiceHandler.obtainMessage();
-        msg.arg1 = startId;
-        msg.obj = intent.getExtras();
-        mServiceHandler.sendMessage(msg);
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        if (intent != null) {
+            Message msg = mServiceHandler.obtainMessage();
+            msg.arg1 = startId;
+            msg.obj = intent.getExtras();
+            mServiceHandler.sendMessage(msg);
+        }
+        return START_REDELIVER_INTENT;
     }
 
     @Override
diff --git a/src/com/android/calendar/CalendarActivity.java b/src/com/android/calendar/CalendarActivity.java
index 2bc991a..b44d519 100644
--- a/src/com/android/calendar/CalendarActivity.java
+++ b/src/com/android/calendar/CalendarActivity.java
@@ -16,9 +16,6 @@
 
 package com.android.calendar;
 
-import dalvik.system.VMRuntime;
-
-import android.accounts.AccountMonitor;
 import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -41,6 +38,8 @@
 import android.widget.ProgressBar;
 import android.widget.ViewSwitcher;
 
+import dalvik.system.VMRuntime;
+
 /**
  * This is the base class for Day and Week Activities.
  */
@@ -53,8 +52,6 @@
 
     private ContentResolver mContentResolver;
 
-    private AccountMonitor mAccountMonitor;
-
     protected ProgressBar mProgressBar;
     protected ViewSwitcher mViewSwitcher;
     protected Animation mInAnimationForward;
@@ -103,7 +100,7 @@
 
         // Eliminate extra GCs during startup by setting the initial heap size to 4MB.
         // TODO: We should restore the old heap size once the activity reaches the idle state
-        long oldHeapSize = VMRuntime.getRuntime().setMinimumHeapSize(INITIAL_HEAP_SIZE);
+        VMRuntime.getRuntime().setMinimumHeapSize(INITIAL_HEAP_SIZE);
 
         setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);
         mContentResolver = getContentResolver();
@@ -128,6 +125,16 @@
     }
 
     @Override
+    protected void onNewIntent(Intent intent) {
+        long timeMillis = Utils.timeFromIntentInMillis(intent);
+        if (timeMillis > 0) {
+            Time time = new Time();
+            time.set(timeMillis);
+            goTo(time, false);
+        }
+    }
+
+    @Override
     protected void onResume() {
         super.onResume();
         mEventLoader.startBackgroundThread();
@@ -153,14 +160,6 @@
     }
 
     @Override
-    protected void onDestroy() {
-        if (mAccountMonitor != null) {
-            mAccountMonitor.close();
-        }
-        super.onDestroy();
-    }
-
-    @Override
     protected void onPause() {
         super.onPause();
         mContentResolver.unregisterContentObserver(mObserver);
@@ -184,15 +183,16 @@
     }
 
     /* Navigator interface methods */
-    public void goTo(Time time) {
-        CalendarView current = (CalendarView) mViewSwitcher.getCurrentView();
-
-        if (current.getSelectedTime().before(time)) {
-            mViewSwitcher.setInAnimation(mInAnimationForward);
-            mViewSwitcher.setOutAnimation(mOutAnimationForward);
-        } else {
-            mViewSwitcher.setInAnimation(mInAnimationBackward);
-            mViewSwitcher.setOutAnimation(mOutAnimationBackward);
+    public void goTo(Time time, boolean animate) {
+        if (animate) {
+            CalendarView current = (CalendarView) mViewSwitcher.getCurrentView();
+            if (current.getSelectedTime().before(time)) {
+                mViewSwitcher.setInAnimation(mInAnimationForward);
+                mViewSwitcher.setOutAnimation(mOutAnimationForward);
+            } else {
+                mViewSwitcher.setInAnimation(mInAnimationBackward);
+                mViewSwitcher.setOutAnimation(mOutAnimationBackward);
+            }
         }
 
         CalendarView next = (CalendarView) mViewSwitcher.getNextView();
@@ -260,7 +260,7 @@
         if (progress > 1.0f) {
             progress = 1.0f;
         }
-        
+
         float inFromXValue, inToXValue;
         float outFromXValue, outToXValue;
         if (forward) {
@@ -274,7 +274,7 @@
             outFromXValue = progress;
             outToXValue = 1.0f;
         }
-        
+
         // We have to allocate these animation objects each time we switch views
         // because that is the only way to set the animation parameters.
         TranslateAnimation inAnimation = new TranslateAnimation(
@@ -288,14 +288,14 @@
                 Animation.RELATIVE_TO_SELF, outToXValue,
                 Animation.ABSOLUTE, 0.0f,
                 Animation.ABSOLUTE, 0.0f);
-        
+
         // Reduce the animation duration based on how far we have already swiped.
         long duration = (long) (ANIMATION_DURATION * (1.0f - progress));
         inAnimation.setDuration(duration);
         outAnimation.setDuration(duration);
         mViewSwitcher.setInAnimation(inAnimation);
         mViewSwitcher.setOutAnimation(outAnimation);
-        
+
         CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
         view.cleanup();
         mViewSwitcher.showNext();
@@ -344,12 +344,6 @@
         }
 
         @Override
-        public void onShowPress(MotionEvent ev) {
-            CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
-            view.doShowPress(ev);
-        }
-
-        @Override
         public void onLongPress(MotionEvent ev) {
             CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
             view.doLongPress(ev);
diff --git a/src/com/android/calendar/CalendarApplication.java b/src/com/android/calendar/CalendarApplication.java
index a3dad95..424e422 100644
--- a/src/com/android/calendar/CalendarApplication.java
+++ b/src/com/android/calendar/CalendarApplication.java
@@ -32,7 +32,7 @@
      * points to the first element in the list (the most recently visited
      * screen).
      */
-    /* package */ class Screen {
+    static class Screen {
         public int id;
         public Screen next;
         public Screen previous;
diff --git a/src/com/android/calendar/CalendarView.java b/src/com/android/calendar/CalendarView.java
index 8db673b..6716edf 100644
--- a/src/com/android/calendar/CalendarView.java
+++ b/src/com/android/calendar/CalendarView.java
@@ -74,6 +74,8 @@
 public class CalendarView extends View
         implements View.OnCreateContextMenuListener, View.OnClickListener {
 
+    private static float mScale = 0; // Used for supporting different screen densities
+
     private boolean mOnFlingCalled;
 
     protected CalendarApplication mCalendarApp;
@@ -82,8 +84,10 @@
     private static final String[] CALENDARS_PROJECTION = new String[] {
         Calendars._ID,          // 0
         Calendars.ACCESS_LEVEL, // 1
+        Calendars.OWNER_ACCOUNT, // 2
     };
     private static final int CALENDARS_INDEX_ACCESS_LEVEL = 1;
+    private static final int CALENDARS_INDEX_OWNER_ACCOUNT = 2;
     private static final String CALENDARS_WHERE = Calendars._ID + "=%d";
 
     private static final String[] ATTENDEES_PROJECTION = new String[] {
@@ -93,7 +97,7 @@
     private static final int ATTENDEES_INDEX_RELATIONSHIP = 1;
     private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=%d";
 
-    private static final float SMALL_ROUND_RADIUS = 3.0F;
+    private static float SMALL_ROUND_RADIUS = 3.0F;
 
     private static final int FROM_NONE = 0;
     private static final int FROM_ABOVE = 1;
@@ -101,11 +105,11 @@
     private static final int FROM_LEFT = 4;
     private static final int FROM_RIGHT = 8;
 
-    private static final int HORIZONTAL_SCROLL_THRESHOLD = 50;
+    private static int HORIZONTAL_SCROLL_THRESHOLD = 50;
 
     private ContinueScroll mContinueScroll = new ContinueScroll();
 
-    private class DayHeader{
+    static private class DayHeader{
         int cell;
         String dateString;
     }
@@ -145,7 +149,6 @@
     boolean mSelectionAllDay;
 
     private int mCellWidth;
-    private boolean mLaunchNewView;
 
     // Pre-allocate these objects and re-use them
     private Rect mRect = new Rect();
@@ -179,10 +182,10 @@
 
     private static final int DAY_GAP = 1;
     private static final int HOUR_GAP = 1;
-    private static final int SINGLE_ALLDAY_HEIGHT = 20;
-    private static final int MAX_ALLDAY_HEIGHT = 72;
-    private static final int ALLDAY_TOP_MARGIN = 3;
-    private static final int MAX_ALLDAY_EVENT_HEIGHT = 18;
+    private static int SINGLE_ALLDAY_HEIGHT = 20;
+    private static int MAX_ALLDAY_HEIGHT = 72;
+    private static int ALLDAY_TOP_MARGIN = 3;
+    private static int MAX_ALLDAY_EVENT_HEIGHT = 18;
     
     /* The extra space to leave above the text in all-day events */
     private static final int ALL_DAY_TEXT_TOP_MARGIN = 0;
@@ -200,13 +203,13 @@
     /* package */ static final int MILLIS_PER_HOUR = (3600 * 1000);
     /* package */ static final int MILLIS_PER_DAY = MILLIS_PER_HOUR * 24;
 
-    private static final int NORMAL_FONT_SIZE = 12;
-    private static final int EVENT_TEXT_FONT_SIZE = 12;
-    private static final int HOURS_FONT_SIZE = 12;
-    private static final int AMPM_FONT_SIZE = 9;
-    private static final int MIN_CELL_WIDTH_FOR_TEXT = 10;
+    private static int NORMAL_FONT_SIZE = 12;
+    private static int EVENT_TEXT_FONT_SIZE = 12;
+    private static int HOURS_FONT_SIZE = 12;
+    private static int AMPM_FONT_SIZE = 9;
+    private static int MIN_CELL_WIDTH_FOR_TEXT = 27;
     private static final int MAX_EVENT_TEXT_LEN = 500;
-    private static final float MIN_EVENT_HEIGHT = 15.0F;  // in pixels
+    private static float MIN_EVENT_HEIGHT = 15.0F;  // in pixels
 
     private static int mSelectionColor;
     private static int mPressedColor;
@@ -307,9 +310,30 @@
 
     private String mDateRange;
     private TextView mTitleTextView;
-    
+
     public CalendarView(CalendarActivity activity) {
         super(activity);
+        if (mScale == 0) {
+            mScale = getContext().getResources().getDisplayMetrics().density;
+            if (mScale != 1) {
+                SINGLE_ALLDAY_HEIGHT *= mScale;
+                MAX_ALLDAY_HEIGHT *= mScale;
+                ALLDAY_TOP_MARGIN *= mScale;
+                MAX_ALLDAY_EVENT_HEIGHT *= mScale;
+
+                NORMAL_FONT_SIZE *= mScale;
+                EVENT_TEXT_FONT_SIZE *= mScale;
+                HOURS_FONT_SIZE *= mScale;
+                AMPM_FONT_SIZE *= mScale;
+                MIN_CELL_WIDTH_FOR_TEXT *= mScale;
+                MIN_EVENT_HEIGHT *= mScale;
+
+                HORIZONTAL_SCROLL_THRESHOLD *= mScale;
+ 
+                SMALL_ROUND_RADIUS *= mScale;
+            }
+        }
+
         mResources = activity.getResources();
         mEventLoader = activity.mEventLoader;
         mEventGeometry = new EventGeometry();
@@ -812,8 +836,7 @@
                 } else {
                     // Switch to the Day/Agenda view.
                     long millis = getSelectedTimeInMillis();
-                    MenuHelper.switchTo(mParentActivity, mDetailedView, millis);
-                    mParentActivity.finish();
+                    Utils.startActivity(mParentActivity, mDetailedView, millis);
                 }
             }
         } else {
@@ -875,6 +898,13 @@
                     performLongClick();
                 }
                 break;
+            case KeyEvent.KEYCODE_BACK:
+                if (event.isTracking() && !event.isCanceled()) {
+                    mPopup.dismiss();
+                    mParentActivity.finish();
+                    return true;
+                }
+                break;
         }
         return super.onKeyUp(keyCode, event);
     }
@@ -924,9 +954,11 @@
             switchViews(true /* trackball or keyboard */);
             return true;
         case KeyEvent.KEYCODE_BACK:
-            mPopup.dismiss();
-            mParentActivity.finish();
-            return true;
+            if (event.getRepeatCount() == 0) {
+                event.startTracking();
+                return true;
+            }
+            return super.onKeyDown(keyCode, event);
         case KeyEvent.KEYCODE_DPAD_LEFT:
             if (mSelectedEvent != null) {
                 mSelectedEvent = mSelectedEvent.nextLeft;
@@ -2303,21 +2335,10 @@
         mTouchMode = TOUCH_MODE_DOWN;
         mViewStartX = 0;
         mOnFlingCalled = false;
-        mLaunchNewView = false;
         getHandler().removeCallbacks(mContinueScroll);
     }
 
     void doSingleTapUp(MotionEvent ev) {
-        mSelectionMode = SELECTION_SELECTED;
-        mRedrawScreen = true;
-        invalidate();
-        if (mLaunchNewView) {
-            mLaunchNewView = false;
-            switchViews(false /* not the trackball */);
-        }
-    }
-
-    void doShowPress(MotionEvent ev) {
         int x = (int) ev.getX();
         int y = (int) ev.getY();
         Event selectedEvent = mSelectedEvent;
@@ -2326,29 +2347,41 @@
 
         boolean validPosition = setSelectionFromPosition(x, y);
         if (!validPosition) {
+            // return if the touch wasn't on an area of concern
             return;
         }
 
-        mSelectionMode = SELECTION_PRESSED;
+        mSelectionMode = SELECTION_SELECTED;
         mRedrawScreen = true;
         invalidate();
 
-        // If the tap is on an already selected event or hour slot,
-        // then launch a new view.  Otherwise, just select the event.
-        if (selectedEvent != null && selectedEvent == mSelectedEvent) {
-            // Launch the "View event" view when the finger lifts up,
-            // unless the finger moves before lifting up.
-            mLaunchNewView = true;
-        } else if (selectedEvent == null && selectedDay == mSelectionDay
+        boolean launchNewView = false;
+        if (mSelectedEvent != null) {
+            // If the tap is on an event, launch the "View event" view
+            launchNewView = true;
+        } else if (mSelectedEvent == null && selectedDay == mSelectionDay
                 && selectedHour == mSelectionHour) {
-            // Launch the Day/Agenda view when the finger lifts up,
-            // unless the finger moves before lifting up.
-            mLaunchNewView = true;
+            // If the tap is on an already selected hour slot,
+            // then launch the Day/Agenda view. Otherwise, just select the hour
+            // slot.
+            launchNewView = true;
+        }
+
+        if (launchNewView) {
+            switchViews(false /* not the trackball */);
         }
     }
 
     void doLongPress(MotionEvent ev) {
-        mLaunchNewView = false;
+        int x = (int) ev.getX();
+        int y = (int) ev.getY();
+
+        boolean validPosition = setSelectionFromPosition(x, y);
+        if (!validPosition) {
+            // return if the touch wasn't on an area of concern
+            return;
+        }
+
         mSelectionMode = SELECTION_LONGPRESS;
         mRedrawScreen = true;
         invalidate();
@@ -2356,7 +2389,6 @@
     }
 
     void doScroll(MotionEvent e1, MotionEvent e2, float deltaX, float deltaY) {
-        mLaunchNewView = false;
         // Use the distance from the current point to the initial touch instead
         // of deltaX and deltaY to avoid accumulating floating-point rounding
         // errors.  Also, we don't need floats, we can use ints.
@@ -2684,14 +2716,12 @@
                 }
                 case MenuHelper.MENU_DAY: {
                     long startMillis = getSelectedTimeInMillis();
-                    MenuHelper.switchTo(mParentActivity, DayActivity.class.getName(), startMillis);
-                    mParentActivity.finish();
+                    Utils.startActivity(mParentActivity, DayActivity.class.getName(), startMillis);
                     break;
                 }
                 case MenuHelper.MENU_AGENDA: {
                     long startMillis = getSelectedTimeInMillis();
-                    MenuHelper.switchTo(mParentActivity, AgendaActivity.class.getName(), startMillis);
-                    mParentActivity.finish();
+                    Utils.startActivity(mParentActivity, AgendaActivity.class.getName(), startMillis);
                     break;
                 }
                 case MenuHelper.MENU_EVENT_CREATE: {
@@ -2746,25 +2776,23 @@
         String where = String.format(CALENDARS_WHERE, calId);
         cursor = cr.query(uri, CALENDARS_PROJECTION, where, null, null);
 
+        String calendarOwnerAccount = null;
         if (cursor != null) {
             cursor.moveToFirst();
             visibility = cursor.getInt(CALENDARS_INDEX_ACCESS_LEVEL);
+            calendarOwnerAccount = cursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
             cursor.close();
         }
-
-        // Attendees cursor
-        uri = Attendees.CONTENT_URI;
-        where = String.format(ATTENDEES_WHERE, e.id);
-        Cursor attendeesCursor = cr.query(uri, ATTENDEES_PROJECTION, where, null, null);
-        if (attendeesCursor != null) {
-            if (attendeesCursor.moveToFirst()) {
-                relationship = attendeesCursor.getInt(ATTENDEES_INDEX_RELATIONSHIP);
-            }
-            attendeesCursor.close();
+        
+        if (visibility < Calendars.CONTRIBUTOR_ACCESS) {
+            return false;
         }
 
-        return visibility >= Calendars.CONTRIBUTOR_ACCESS &&
-                relationship >= Attendees.RELATIONSHIP_ORGANIZER;
+        if (e.guestsCanModify) {
+            return true;
+        }
+
+        return !TextUtils.isEmpty(calendarOwnerAccount) && calendarOwnerAccount.equals(e.organizer);
     }
 
     /**
diff --git a/src/com/android/calendar/DayActivity.java b/src/com/android/calendar/DayActivity.java
index 51f965b..e2bf14c 100644
--- a/src/com/android/calendar/DayActivity.java
+++ b/src/com/android/calendar/DayActivity.java
@@ -16,9 +16,7 @@
 
 package com.android.calendar;
 
-import android.content.SharedPreferences;
 import android.os.Bundle;
-import android.preference.PreferenceManager;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
 import android.widget.ProgressBar;
@@ -42,16 +40,6 @@
         mViewSwitcher.setFactory(this);
         mViewSwitcher.getCurrentView().requestFocus();
         mProgressBar = (ProgressBar) findViewById(R.id.progress_circular);
-
-        // Record Day View as the (new) default detailed view.
-        String activityString = CalendarApplication.ACTIVITY_NAMES[CalendarApplication.DAY_VIEW_ID];
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
-        SharedPreferences.Editor editor = prefs.edit();
-        editor.putString(CalendarPreferenceActivity.KEY_DETAILED_VIEW, activityString);
-
-        // Record Day View as the (new) start view
-        editor.putString(CalendarPreferenceActivity.KEY_START_VIEW, activityString);
-        editor.commit();
     }
 
     public View makeView() {
@@ -68,5 +56,8 @@
         super.onPause();
         CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
         mSelectedDay = view.getSelectedDay();
+
+        // Record Day View as the (new) default detailed view.
+        Utils.setDefaultView(this, CalendarApplication.DAY_VIEW_ID);
     }
 }
diff --git a/src/com/android/calendar/DeleteEventHelper.java b/src/com/android/calendar/DeleteEventHelper.java
index d0693fa..bf27a9e 100644
--- a/src/com/android/calendar/DeleteEventHelper.java
+++ b/src/com/android/calendar/DeleteEventHelper.java
@@ -52,8 +52,6 @@
  * {@link #delete()} multiple times).
  */
 public class DeleteEventHelper {
-    
-    private static final String TAG = "DeleteEventHelper";
     private final Activity mParent;
     private final ContentResolver mContentResolver;
     
diff --git a/src/com/android/calendar/EditEvent.java b/src/com/android/calendar/EditEvent.java
index ce545fa..9438419 100644
--- a/src/com/android/calendar/EditEvent.java
+++ b/src/com/android/calendar/EditEvent.java
@@ -18,6 +18,11 @@
 
 import static android.provider.Calendar.EVENT_BEGIN_TIME;
 import static android.provider.Calendar.EVENT_END_TIME;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.DatePickerDialog;
@@ -26,30 +31,41 @@
 import android.app.DatePickerDialog.OnDateSetListener;
 import android.app.TimePickerDialog.OnTimeSetListener;
 import android.content.AsyncQueryHandler;
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.OperationApplicationException;
 import android.content.SharedPreferences;
+import android.content.ContentProviderOperation.Builder;
 import android.content.DialogInterface.OnCancelListener;
 import android.content.DialogInterface.OnClickListener;
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.RemoteException;
 import android.pim.EventRecurrence;
 import android.preference.PreferenceManager;
+import android.provider.Calendar.Attendees;
 import android.provider.Calendar.Calendars;
 import android.provider.Calendar.Events;
 import android.provider.Calendar.Reminders;
+import android.text.Editable;
+import android.text.InputFilter;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
 import android.text.format.DateUtils;
 import android.text.format.Time;
+import android.text.util.Rfc822InputFilter;
+import android.text.util.Rfc822Token;
+import android.text.util.Rfc822Tokenizer;
+import android.text.util.Rfc822Validator;
 import android.util.Log;
-import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -62,19 +78,28 @@
 import android.widget.DatePicker;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
+import android.widget.MultiAutoCompleteTextView;
 import android.widget.ResourceCursorAdapter;
 import android.widget.Spinner;
 import android.widget.TextView;
 import android.widget.TimePicker;
 import android.widget.Toast;
 
+import com.google.android.googlelogin.GoogleLoginServiceConstants;
+
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.TimeZone;
 
 public class EditEvent extends Activity implements View.OnClickListener,
         DialogInterface.OnCancelListener, DialogInterface.OnClickListener {
+    private static final String TAG = "EditEvent";
+    private static final boolean DEBUG = false;
+
     /**
      * This is the symbolic name for the key used to pass in the boolean
      * for creating all-day events that is part of the extra data of the intent.
@@ -94,20 +119,22 @@
     private static final int MENU_HIDE_EXTRA_OPTIONS = 3;
 
     private static final String[] EVENT_PROJECTION = new String[] {
-            Events._ID,             // 0
-            Events.TITLE,           // 1
-            Events.DESCRIPTION,     // 2
-            Events.EVENT_LOCATION,  // 3
-            Events.ALL_DAY,         // 4
-            Events.HAS_ALARM,       // 5
-            Events.CALENDAR_ID,     // 6
-            Events.DTSTART,         // 7
-            Events.DURATION,        // 8
-            Events.EVENT_TIMEZONE,  // 9
-            Events.RRULE,           // 10
-            Events._SYNC_ID,        // 11
-            Events.TRANSPARENCY,    // 12
-            Events.VISIBILITY,      // 13
+            Events._ID,               // 0
+            Events.TITLE,             // 1
+            Events.DESCRIPTION,       // 2
+            Events.EVENT_LOCATION,    // 3
+            Events.ALL_DAY,           // 4
+            Events.HAS_ALARM,         // 5
+            Events.CALENDAR_ID,       // 6
+            Events.DTSTART,           // 7
+            Events.DURATION,          // 8
+            Events.EVENT_TIMEZONE,    // 9
+            Events.RRULE,             // 10
+            Events._SYNC_ID,          // 11
+            Events.TRANSPARENCY,      // 12
+            Events.VISIBILITY,        // 13
+            Events.OWNER_ACCOUNT,     // 14
+            Events.HAS_ATTENDEE_DATA, // 15
     };
     private static final int EVENT_INDEX_ID = 0;
     private static final int EVENT_INDEX_TITLE = 1;
@@ -123,14 +150,16 @@
     private static final int EVENT_INDEX_SYNC_ID = 11;
     private static final int EVENT_INDEX_TRANSPARENCY = 12;
     private static final int EVENT_INDEX_VISIBILITY = 13;
+    private static final int EVENT_INDEX_OWNER_ACCOUNT = 14;
+    private static final int EVENT_INDEX_HAS_ATTENDEE_DATA = 15;
 
     private static final String[] CALENDARS_PROJECTION = new String[] {
-            Calendars._ID,          // 0
-            Calendars.DISPLAY_NAME, // 1
-            Calendars.TIMEZONE,     // 2
+            Calendars._ID,           // 0
+            Calendars.DISPLAY_NAME,  // 1
+            Calendars.OWNER_ACCOUNT, // 2
     };
     private static final int CALENDARS_INDEX_DISPLAY_NAME = 1;
-    private static final int CALENDARS_INDEX_TIMEZONE = 2;
+    private static final int CALENDARS_INDEX_OWNER_ACCOUNT = 2;
     private static final String CALENDARS_WHERE = Calendars.ACCESS_LEVEL + ">=" +
             Calendars.CONTRIBUTOR_ACCESS + " AND " + Calendars.SYNC_EVENTS + "=1";
 
@@ -143,6 +172,17 @@
             Reminders.METHOD + "=" + Reminders.METHOD_ALERT + " OR " + Reminders.METHOD + "=" +
             Reminders.METHOD_DEFAULT + ")";
 
+    private static final String[] ATTENDEES_PROJECTION = new String[] {
+        Attendees.ATTENDEE_NAME,            // 0
+        Attendees.ATTENDEE_EMAIL,           // 1
+    };
+    private static final int ATTENDEES_INDEX_NAME = 0;
+    private static final int ATTENDEES_INDEX_EMAIL = 1;
+    private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=? AND "
+            + Attendees.ATTENDEE_RELATIONSHIP + "<>" + Attendees.RELATIONSHIP_ORGANIZER;
+    private static final String ATTENDEES_DELETE_PREFIX = Attendees.EVENT_ID + "=? AND " +
+            Attendees.ATTENDEE_EMAIL + " IN (";
+
     private static final int DOES_NOT_REPEAT = 0;
     private static final int REPEATS_DAILY = 1;
     private static final int REPEATS_EVERY_WEEKDAY = 2;
@@ -156,7 +196,7 @@
     private static final int MODIFY_SELECTED = 1;
     private static final int MODIFY_ALL = 2;
     private static final int MODIFY_ALL_FOLLOWING = 3;
-    
+
     private static final int DAY_IN_SECONDS = 24 * 60 * 60;
 
     private int mFirstDayOfWeek; // cached in onCreate
@@ -184,6 +224,13 @@
     private LinearLayout mExtraOptions;
     private ArrayList<Integer> mOriginalMinutes = new ArrayList<Integer>();
     private ArrayList<LinearLayout> mReminderItems = new ArrayList<LinearLayout>(0);
+    private Rfc822Validator mEmailValidator;
+    private MultiAutoCompleteTextView mAttendeesList;
+    private EmailAddressAdapter mAddressAdapter;
+    private String mOriginalAttendees = "";
+
+    // Used to control the visibility of the Guests textview. Default to true
+    private boolean mHasAttendeeData = true;
 
     private EventRecurrence mEventRecurrence = new EventRecurrence();
     private String mRrule;
@@ -192,6 +239,7 @@
     private ProgressDialog mLoadingCalendarsDialog;
     private AlertDialog mNoCalendarsDialog;
     private ContentValues mInitialValues;
+    private String mOwnerAccount;
 
     /**
      * If the repeating event is created on the phone and it hasn't been
@@ -214,7 +262,8 @@
 
     private DeleteEventHelper mDeleteEventHelper;
     private QueryHandler mQueryHandler;
-    
+    private AccountManager mAccountManager;
+
     /* This class is used to update the time buttons. */
     private class TimeListener implements OnTimeSetListener {
         private View mView;
@@ -350,7 +399,7 @@
         }
     }
 
-    private class CalendarsAdapter extends ResourceCursorAdapter {
+    static private class CalendarsAdapter extends ResourceCursorAdapter {
         public CalendarsAdapter(Context context, Cursor c) {
             super(context, R.layout.calendars_item, c);
             setDropDownViewResource(R.layout.calendars_dropdown_item);
@@ -373,7 +422,7 @@
             }
             return;
         }
-        
+
         if (v == mDeleteButton) {
             long begin = mStartTime.toMillis(false /* use isDst */);
             long end = mEndTime.toMillis(false /* use isDst */);
@@ -392,12 +441,12 @@
             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();
@@ -426,7 +475,7 @@
             finish();
         }
     }
-    
+
     private class QueryHandler extends AsyncQueryHandler {
         public QueryHandler(ContentResolver cr) {
             super(cr);
@@ -442,7 +491,7 @@
             } else {
                 mCalendarsCursor = cursor;
                 startManagingCursor(cursor);
-                
+
                 // Stop the spinner
                 getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
                         Window.PROGRESS_VISIBILITY_OFF);
@@ -454,7 +503,7 @@
                     if (mSaveAfterQueryComplete) {
                         mLoadingCalendarsDialog.cancel();
                     }
-                    
+
                     // Create an error message for the user that, when clicked,
                     // will exit this activity without saving the event.
                     AlertDialog.Builder builder = new AlertDialog.Builder(EditEvent.this);
@@ -467,17 +516,87 @@
                     return;
                 }
 
+                int primaryCalendarPosition = findPrimaryCalendarPosition();
+
                 // populate the calendars spinner
                 CalendarsAdapter adapter = new CalendarsAdapter(EditEvent.this, mCalendarsCursor);
                 mCalendarsSpinner.setAdapter(adapter);
+                mCalendarsSpinner.setSelection(primaryCalendarPosition);
                 mCalendarsQueryComplete = true;
                 if (mSaveAfterQueryComplete) {
                     mLoadingCalendarsDialog.cancel();
                     save();
                     finish();
                 }
+
+                // Find user domain and set it to the validator.
+                // TODO: we may want to update this validator if the user actually picks
+                // a different calendar.  maybe not.  depends on what we want for the
+                // user experience.  this may change when we add support for multiple
+                // accounts, anyway.
+                if (mHasAttendeeData && cursor.moveToPosition(primaryCalendarPosition)) {
+                    String ownEmail = cursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
+                    if (ownEmail != null) {
+                        String domain = extractDomain(ownEmail);
+                        if (domain != null) {
+                            mEmailValidator = new Rfc822Validator(domain);
+                            mAttendeesList.setValidator(mEmailValidator);
+                        }
+                    }
+                }
             }
         }
+
+        // Find the calendar position in the cursor that matches the signed-in
+        // account
+        private int findPrimaryCalendarPosition() {
+            int primaryCalendarPosition = -1;
+            try {
+                Account[] accounts = mAccountManager.getAccountsByTypeAndFeatures(
+                        GoogleLoginServiceConstants.ACCOUNT_TYPE, new String[] {
+                            GoogleLoginServiceConstants.FEATURE_LEGACY_HOSTED_OR_GOOGLE
+                        }, null, null).getResult();
+                if (accounts.length > 0) {
+                    for (int i = 0; i < accounts.length && primaryCalendarPosition == -1; ++i) {
+                        String name = accounts[i].name;
+                        if (name == null) {
+                            continue;
+                        }
+
+                        int position = 0;
+                        mCalendarsCursor.moveToPosition(-1);
+                        while (mCalendarsCursor.moveToNext()) {
+                            if (name.equals(mCalendarsCursor
+                                    .getString(CALENDARS_INDEX_OWNER_ACCOUNT))) {
+                                primaryCalendarPosition = position;
+                                break;
+                            }
+                            position++;
+                        }
+                    }
+                }
+            } catch (OperationCanceledException e) {
+                Log.w(TAG, "Ignoring unexpected exception", e);
+            } catch (IOException e) {
+                Log.w(TAG, "Ignoring unexpected exception", e);
+            } catch (AuthenticatorException e) {
+                Log.w(TAG, "Ignoring unexpected exception", e);
+            } finally {
+                if (primaryCalendarPosition != -1) {
+                    return primaryCalendarPosition;
+                } else {
+                    return 0;
+                }
+            }
+        }
+    }
+
+    private static String extractDomain(String email) {
+        int separator = email.lastIndexOf('@');
+        if (separator != -1 && ++separator < email.length()) {
+            return email.substring(separator);
+        }
+        return null;
     }
 
     @Override
@@ -485,6 +604,9 @@
         super.onCreate(icicle);
         requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
         setContentView(R.layout.edit_event);
+        mAccountManager = AccountManager.get(this);
+
+        boolean newEvent = false;
 
         mFirstDayOfWeek = Calendar.getInstance().getFirstDayOfWeek();
 
@@ -506,15 +628,25 @@
         long begin = intent.getLongExtra(EVENT_BEGIN_TIME, 0);
         long end = intent.getLongExtra(EVENT_END_TIME, 0);
 
+        String domain = "gmail.com";
+
         boolean allDay = false;
         if (mEventCursor != null) {
             // The event already exists so fetch the all-day status
             mEventCursor.moveToFirst();
+            mHasAttendeeData = mEventCursor.getInt(EVENT_INDEX_HAS_ATTENDEE_DATA) != 0;
             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);
-            
+            mOwnerAccount = mEventCursor.getString(EVENT_INDEX_OWNER_ACCOUNT);
+            if (!TextUtils.isEmpty(mOwnerAccount)) {
+                String ownerDomain = extractDomain(mOwnerAccount);
+                if (ownerDomain != null) {
+                    domain = ownerDomain;
+                }
+            }
+
             // Remember the initial values
             mInitialValues = new ContentValues();
             mInitialValues.put(EVENT_BEGIN_TIME, begin);
@@ -524,10 +656,11 @@
             mInitialValues.put(Events.EVENT_TIMEZONE, timezone);
             mInitialValues.put(Events.CALENDAR_ID, calendarId);
         } else {
+            newEvent = true;
             // 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);
@@ -584,6 +717,14 @@
         mRemindersContainer = (LinearLayout) findViewById(R.id.reminder_items_container);
         mExtraOptions = (LinearLayout) findViewById(R.id.extra_options_container);
 
+        if (mHasAttendeeData) {
+            mAddressAdapter = new EmailAddressAdapter(this);
+            mEmailValidator = new Rfc822Validator(domain);
+            mAttendeesList = initMultiAutoCompleteTextView(R.id.attendees);
+        } else {
+            findViewById(R.id.attendees_group).setVisibility(View.GONE);
+        }
+
         mAllDayCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
             public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                 if (isChecked) {
@@ -648,14 +789,20 @@
                 prefs.getString(CalendarPreferenceActivity.KEY_DEFAULT_REMINDER, "0");
         mDefaultReminderMinutes = Integer.parseInt(durationString);
 
+        if (newEvent && mDefaultReminderMinutes != 0) {
+            addReminder(this, this, mReminderItems, mReminderValues,
+                    mReminderLabels, mDefaultReminderMinutes);
+        }
+
+        long eventId = (mEventCursor == null) ? -1 : mEventCursor.getLong(EVENT_INDEX_ID);
+        ContentResolver cr = getContentResolver();
+
         // 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.,
@@ -664,7 +811,7 @@
                     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()) {
@@ -684,45 +831,109 @@
             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 */);
 
+       // Attendees cursor
+        if (mHasAttendeeData && eventId != -1) {
+            Uri uri = Attendees.CONTENT_URI;
+            String[] whereArgs = {Long.toString(eventId)};
+            Cursor attendeeCursor = cr.query(uri, ATTENDEES_PROJECTION, ATTENDEES_WHERE, whereArgs,
+                    null);
+            try {
+                StringBuilder b = new StringBuilder();
+                while (attendeeCursor.moveToNext()) {
+                    String name = attendeeCursor.getString(ATTENDEES_INDEX_NAME);
+                    String email = attendeeCursor.getString(ATTENDEES_INDEX_EMAIL);
+                    if (email != null) {
+                        if (name != null && name.length() > 0 && !name.equals(email)) {
+                            b.append('"').append(name).append("\" ");
+                        }
+                        b.append('<').append(email).append(">, ");
+                    }
+                }
+                if (b.length() > 0) {
+                    mOriginalAttendees = b.toString();
+                    mAttendeesList.setText(mOriginalAttendees);
+                }
+            } finally {
+                attendeeCursor.close();
+            }
+        }
         if (mEventCursor == null) {
             // Allow the intent to specify the fields in the event.
             // This will allow other apps to create events easily.
             initFromIntent(intent);
         }
     }
-    
+
+    private LinkedHashSet<Rfc822Token> getAddressesFromList(MultiAutoCompleteTextView list) {
+        list.clearComposingText();
+        LinkedHashSet<Rfc822Token> addresses = new LinkedHashSet<Rfc822Token>();
+        Rfc822Tokenizer.tokenize(list.getText(), addresses);
+
+        // validate the emails, out of paranoia.  they should already be
+        // validated on input, but drop any invalid emails just to be safe.
+        for (Rfc822Token address : addresses) {
+            if (!mEmailValidator.isValid(address.getAddress())) {
+                Log.w(TAG, "Dropping invalid attendee email address: " + address);
+                addresses.remove(address);
+            }
+        }
+        return addresses;
+    }
+
+    // From com.google.android.gm.ComposeActivity
+    private MultiAutoCompleteTextView initMultiAutoCompleteTextView(int res) {
+        MultiAutoCompleteTextView list = (MultiAutoCompleteTextView) findViewById(res);
+        list.setAdapter(mAddressAdapter);
+        list.setTokenizer(new Rfc822Tokenizer());
+        list.setValidator(mEmailValidator);
+
+        // NOTE: assumes no other filters are set
+        list.setFilters(sRecipientFilters);
+
+        return list;
+    }
+
+    /**
+     * From com.google.android.gm.ComposeActivity
+     * Implements special address cleanup rules:
+     * The first space key entry following an "@" symbol that is followed by any combination
+     * of letters and symbols, including one+ dots and zero commas, should insert an extra
+     * comma (followed by the space).
+     */
+    private static InputFilter[] sRecipientFilters = new InputFilter[] { new Rfc822InputFilter() };
+
     private void initFromIntent(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;
@@ -741,7 +952,7 @@
                 return;
             }
         }
-        
+
         if (mEventCursor != null) {
             Cursor cursor = mEventCursor;
             cursor.moveToFirst();
@@ -795,7 +1006,7 @@
                                 } 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) {
@@ -819,26 +1030,23 @@
             // 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);
+            // New event
+            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);
             }
 
             // Hide delete button
@@ -919,23 +1127,18 @@
     }
 
     @Override
-    public boolean onKeyDown(int keyCode, 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;
+    public void onBackPressed() {
+        // 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;
+            }
         }
-
-        return super.onKeyDown(keyCode, event);
+        finish();
     }
 
     private void populateWhen() {
@@ -1069,7 +1272,7 @@
         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));
@@ -1077,7 +1280,7 @@
         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);
@@ -1088,17 +1291,17 @@
 
         return true;
     }
-    
+
     static void addMinutesToList(Context context, ArrayList<Integer> values,
             ArrayList<String> 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++) {
@@ -1108,14 +1311,14 @@
                 return;
             }
         }
-        
+
         values.add(minutes);
         labels.add(len, label);
     }
-    
+
     /**
      * Finds the index of the given "minutes" in the "values" list.
-     * 
+     *
      * @param values the list of minutes corresponding to the spinner choices
      * @param minutes the minutes to search for in the values list
      * @return the index of "minutes" in the "values" list
@@ -1129,7 +1332,7 @@
         }
         return index;
     }
-    
+
     // Constructs a label given an arbitrary number of minutes.  For example,
     // if the given minutes is 63, then this returns the string "63 minutes".
     // As another example, if the given minutes is 120, then this returns
@@ -1137,7 +1340,7 @@
     static String constructReminderLabel(Context context, int minutes, boolean abbrev) {
         Resources resources = context.getResources();
         int value, resId;
-        
+
         if (minutes % 60 != 0) {
             value = minutes;
             if (abbrev) {
@@ -1185,7 +1388,7 @@
     // Saves the event.  Returns true if it is okay to exit this activity.
     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) {
@@ -1215,30 +1418,42 @@
             Toast.makeText(this, R.string.saving_event, Toast.LENGTH_SHORT).show();
         }
 
-        ContentResolver cr = getContentResolver();
+        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
+        int eventIdIndex = -1;
+
         ContentValues values = getContentValuesFromUi();
         Uri uri = mUri;
 
+        // Update the "hasAlarm" field for the event
+        ArrayList<Integer> reminderMinutes = reminderItemsToMinutes(mReminderItems,
+                mReminderValues);
+        int len = reminderMinutes.size();
+        values.put(Events.HAS_ALARM, (len > 0) ? 1 : 0);
+
         // For recurring events, we must make sure that we use duration rather
         // than dtend.
         if (uri == null) {
+            // Add hasAttendeeData for a new event
+            values.put(Events.HAS_ATTENDEE_DATA, 1);
             // Create new event with new contents
             addRecurrenceRule(values);
-            uri = cr.insert(Events.CONTENT_URI, values);
+            eventIdIndex = ops.size();
+            Builder b = ContentProviderOperation.newInsert(Events.CONTENT_URI).withValues(values);
+            ops.add(b.build());
             forceSaveReminders = true;
 
         } else if (mRrule == null) {
             // Modify contents of a non-repeating event
             addRecurrenceRule(values);
             checkTimeDependentFields(values);
-            cr.update(uri, values, null, null);
-            
+            ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());
+
         } 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);
+            ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());
 
         } else if (mModification == MODIFY_SELECTED) {
             // Modify contents of the current instance of repeating event
@@ -1250,7 +1465,9 @@
             boolean allDay = mInitialValues.getAsInteger(Events.ALL_DAY) != 0;
             values.put(Events.ORIGINAL_ALL_DAY, allDay ? 1 : 0);
 
-            uri = cr.insert(Events.CONTENT_URI, values);
+            eventIdIndex = ops.size();
+            Builder b = ContentProviderOperation.newInsert(Events.CONTENT_URI).withValues(values);
+            ops.add(b.build());
             forceSaveReminders = true;
 
         } else if (mModification == MODIFY_ALL_FOLLOWING) {
@@ -1263,56 +1480,185 @@
                 // then delete the whole series.  Otherwise, update the series
                 // to end at the new start time.
                 if (isFirstEventInSeries()) {
-                    cr.delete(uri, null, null);
+                    ops.add(ContentProviderOperation.newDelete(uri).build());
                 } else {
                     // Update the current repeating event to end at the new
                     // start time.
-                    updatePastEvents(cr, uri);
+                    updatePastEvents(ops, uri);
                 }
-                uri = cr.insert(Events.CONTENT_URI, values);
+                eventIdIndex = ops.size();
+                ops.add(ContentProviderOperation.newInsert(Events.CONTENT_URI).withValues(values)
+                        .build());
             } else {
                 if (isFirstEventInSeries()) {
                     checkTimeDependentFields(values);
                     values.remove(Events.DTEND);
-                    cr.update(uri, values, null, null);
+                    Builder b = ContentProviderOperation.newUpdate(uri).withValues(values);
+                    ops.add(b.build());
                 } else {
                     // Update the current repeating event to end at the new
                     // start time.
-                    updatePastEvents(cr, uri);
+                    updatePastEvents(ops, uri);
 
                     // Create a new event with the user-modified fields
                     values.remove(Events.DTEND);
-                    uri = cr.insert(Events.CONTENT_URI, values);
+                    eventIdIndex = ops.size();
+                    ops.add(ContentProviderOperation.newInsert(Events.CONTENT_URI).withValues(
+                            values).build());
                 }
             }
             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);
+                ops.add(ContentProviderOperation.newDelete(uri).build());
+
+                eventIdIndex = ops.size();
+                ops.add(ContentProviderOperation.newInsert(Events.CONTENT_URI).withValues(values)
+                        .build());
                 forceSaveReminders = true;
             } else {
                 checkTimeDependentFields(values);
                 values.remove(Events.DTEND);
-                cr.update(uri, values, null, null);
+                ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());
             }
         }
 
-        if (uri != null) {
+        // New Event or New Exception to an existing event
+        boolean newEvent = (eventIdIndex != -1);
+
+        if (newEvent) {
+            saveRemindersWithBackRef(ops, eventIdIndex, reminderMinutes, mOriginalMinutes,
+                    forceSaveReminders);
+        } else if (uri != null) {
             long eventId = ContentUris.parseId(uri);
-            ArrayList<Integer> reminderMinutes = reminderItemsToMinutes(mReminderItems,
-                    mReminderValues);
-            saveReminders(cr, eventId, reminderMinutes, mOriginalMinutes,
+            saveReminders(ops, eventId, reminderMinutes, mOriginalMinutes,
                     forceSaveReminders);
         }
+
+        Builder b;
+
+        // New event/instance - Set Organizer's response as yes
+        if (mHasAttendeeData && newEvent) {
+            values.clear();
+            int calendarCursorPosition = mCalendarsSpinner.getSelectedItemPosition();
+            String ownerEmail = mOwnerAccount;
+            // Just in case mOwnerAccount is null, try to get owner from mCalendarsCursor
+            if (ownerEmail == null && mCalendarsCursor != null &&
+                    mCalendarsCursor.moveToPosition(calendarCursorPosition)) {
+                ownerEmail = mCalendarsCursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
+            }
+            if (ownerEmail != null) {
+                values.put(Attendees.ATTENDEE_EMAIL, ownerEmail);
+                values.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ORGANIZER);
+                values.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_NONE);
+                values.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_ACCEPTED);
+
+                b = ContentProviderOperation.newInsert(Attendees.CONTENT_URI)
+                        .withValues(values);
+                b.withValueBackReference(Reminders.EVENT_ID, eventIdIndex);
+                ops.add(b.build());
+            }
+        }
+
+        // TODO: is this the right test?  this currently checks if this is
+        // a new event or an existing event.  or is this a paranoia check?
+        if (mHasAttendeeData && (newEvent || uri != null)) {
+            Editable attendeesText = mAttendeesList.getText();
+            // Hit the content provider only if this is a new event or the user has changed it
+            if (newEvent || !mOriginalAttendees.equals(attendeesText.toString())) {
+                // figure out which attendees need to be added and which ones
+                // need to be deleted.  use a linked hash set, so we maintain
+                // order (but also remove duplicates).
+                LinkedHashSet<Rfc822Token> newAttendees = getAddressesFromList(mAttendeesList);
+
+                // the eventId is only used if eventIdIndex is -1.
+                // TODO: clean up this code.
+                long eventId = uri != null ? ContentUris.parseId(uri) : -1;
+
+                // only compute deltas if this is an existing event.
+                // new events (being inserted into the Events table) won't
+                // have any existing attendees.
+                if (!newEvent) {
+                    HashSet<Rfc822Token> removedAttendees = new HashSet<Rfc822Token>();
+                    HashSet<Rfc822Token> originalAttendees = new HashSet<Rfc822Token>();
+                    Rfc822Tokenizer.tokenize(mOriginalAttendees, originalAttendees);
+                    for (Rfc822Token originalAttendee : originalAttendees) {
+                        if (newAttendees.contains(originalAttendee)) {
+                            // existing attendee.  remove from new attendees set.
+                            newAttendees.remove(originalAttendee);
+                        } else {
+                            // no longer in attendees.  mark as removed.
+                            removedAttendees.add(originalAttendee);
+                        }
+                    }
+
+                    // delete removed attendees
+                    b = ContentProviderOperation.newDelete(Attendees.CONTENT_URI);
+
+                    String[] args = new String[removedAttendees.size() + 1];
+                    args[0] = Long.toString(eventId);
+                    int i = 1;
+                    StringBuilder deleteWhere = new StringBuilder(ATTENDEES_DELETE_PREFIX);
+                    for (Rfc822Token removedAttendee : removedAttendees) {
+                        if (i > 1) {
+                            deleteWhere.append(",");
+                        }
+                        deleteWhere.append("?");
+                        args[i++] = removedAttendee.getAddress();
+                    }
+                    deleteWhere.append(")");
+                    b.withSelection(deleteWhere.toString(), args);
+                    ops.add(b.build());
+                }
+
+                if (newAttendees.size() > 0) {
+                    // Insert the new attendees
+                    for (Rfc822Token attendee : newAttendees) {
+                        values.clear();
+                        values.put(Attendees.ATTENDEE_NAME, attendee.getName());
+                        values.put(Attendees.ATTENDEE_EMAIL, attendee.getAddress());
+                        values.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
+                        values.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_NONE);
+                        values.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_NONE);
+
+                        if (newEvent) {
+                            b = ContentProviderOperation.newInsert(Attendees.CONTENT_URI)
+                                    .withValues(values);
+                            b.withValueBackReference(Attendees.EVENT_ID, eventIdIndex);
+                        } else {
+                            values.put(Attendees.EVENT_ID, eventId);
+                            b = ContentProviderOperation.newInsert(Attendees.CONTENT_URI)
+                                    .withValues(values);
+                        }
+                        ops.add(b.build());
+                    }
+                }
+            }
+        }
+
+        try {
+            // TODO Move this to background thread
+            ContentProviderResult[] results =
+                getContentResolver().applyBatch(android.provider.Calendar.AUTHORITY, ops);
+            if (DEBUG) {
+                for (int i = 0; i < results.length; i++) {
+                    Log.v(TAG, "results = " + results[i].toString());
+                }
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "Ignoring unexpected remote exception", e);
+        } catch (OperationApplicationException e) {
+            Log.w(TAG, "Ignoring unexpected exception", e);
+        }
+
         return true;
     }
 
@@ -1322,7 +1668,7 @@
         return start == mStartTime.toMillis(true);
     }
 
-    private void updatePastEvents(ContentResolver cr, Uri uri) {
+    private void updatePastEvents(ArrayList<ContentProviderOperation> ops, 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;
@@ -1338,17 +1684,17 @@
         // 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) 
+        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.
@@ -1364,7 +1710,8 @@
         oldValues.put(Events.DTSTART, oldStartMillis);
         oldValues.put(Events.DURATION, oldDuration);
         oldValues.put(Events.RRULE, mEventRecurrence.toString());
-        cr.update(uri, oldValues, null, null);
+        Builder b = ContentProviderOperation.newUpdate(uri).withValues(oldValues);
+        ops.add(b.build());
     }
 
     private void checkTimeDependentFields(ContentValues values) {
@@ -1373,13 +1720,13 @@
         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)
@@ -1414,7 +1761,7 @@
             values.put(Events.DTSTART, oldStartMillis);
         }
     }
-    
+
     static ArrayList<Integer> reminderItemsToMinutes(ArrayList<LinearLayout> reminderItems,
             ArrayList<Integer> reminderValues) {
         int len = reminderItems.size();
@@ -1431,8 +1778,8 @@
     /**
      * Saves the reminders, if they changed.  Returns true if the database
      * was updated.
-     * 
-     * @param cr the ContentResolver
+     *
+     * @param ops the array of ContentProviderOperations
      * @param eventId the id of the event whose reminders are being updated
      * @param reminderMinutes the array of reminders set by the user
      * @param originalMinutes the original array of reminders
@@ -1440,7 +1787,7 @@
      *   change
      * @return true if the database was updated
      */
-    static boolean saveReminders(ContentResolver cr, long eventId,
+    static boolean saveReminders(ArrayList<ContentProviderOperation> ops, long eventId,
             ArrayList<Integer> reminderMinutes, ArrayList<Integer> originalMinutes,
             boolean forceSave) {
         // If the reminders have not changed, then don't update the database
@@ -1451,14 +1798,12 @@
         // 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);
+        Builder b = ContentProviderOperation.newDelete(Reminders.CONTENT_URI);
+        b.withSelection(where, args);
+        ops.add(b.build());
 
-        // 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++) {
@@ -1468,7 +1813,39 @@
             values.put(Reminders.MINUTES, minutes);
             values.put(Reminders.METHOD, Reminders.METHOD_ALERT);
             values.put(Reminders.EVENT_ID, eventId);
-            cr.insert(Reminders.CONTENT_URI, values);
+            b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(values);
+            ops.add(b.build());
+        }
+        return true;
+    }
+
+    static boolean saveRemindersWithBackRef(ArrayList<ContentProviderOperation> ops,
+            int eventIdIndex, ArrayList<Integer> reminderMinutes,
+            ArrayList<Integer> originalMinutes, boolean forceSave) {
+        // 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
+        Builder b = ContentProviderOperation.newDelete(Reminders.CONTENT_URI);
+        b.withSelection(Reminders.EVENT_ID + "=?", new String[1]);
+        b.withSelectionBackReference(0, eventIdIndex);
+        ops.add(b.build());
+
+        ContentValues values = new ContentValues();
+        int len = reminderMinutes.size();
+
+        // 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);
+            b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(values);
+            b.withValueBackReference(Reminders.EVENT_ID, eventIdIndex);
+            ops.add(b.build());
         }
         return true;
     }
@@ -1479,7 +1856,7 @@
         if (mRrule == null) {
             return;
         }
-        
+
         values.put(Events.RRULE, mRrule);
         long end = mEndTime.toMillis(true /* ignore dst */);
         long start = mStartTime.toMillis(true /* ignore dst */);
@@ -1599,7 +1976,7 @@
             mEndTime.monthDay++;
             mEndTime.timezone = timezone;
             endMillis = mEndTime.normalize(true);
-            
+
             if (mEventCursor == null) {
                 // This is a new event
                 calendarId = mCalendarsSpinner.getSelectedItemId();
@@ -1612,7 +1989,7 @@
             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.
@@ -1623,7 +2000,7 @@
             } 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();
diff --git a/src/com/android/calendar/EmailAddressAdapter.java b/src/com/android/calendar/EmailAddressAdapter.java
new file mode 100644
index 0000000..bfcb986
--- /dev/null
+++ b/src/com/android/calendar/EmailAddressAdapter.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+package com.android.calendar;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.text.util.Rfc822Token;
+import android.view.View;
+import android.widget.ResourceCursorAdapter;
+import android.widget.TextView;
+
+// Customized from com.android.email.EmailAddressAdapter
+
+public class EmailAddressAdapter extends ResourceCursorAdapter {
+    public static final int NAME_INDEX = 1;
+    public static final int DATA_INDEX = 2;
+
+    private static final String SORT_ORDER =
+            Contacts.TIMES_CONTACTED + " DESC, " + Contacts.DISPLAY_NAME;
+
+    private ContentResolver mContentResolver;
+
+    private static final String[] PROJECTION = {
+        Data._ID,               // 0
+        Contacts.DISPLAY_NAME,  // 1
+        Email.DATA              // 2
+    };
+
+    public EmailAddressAdapter(Context context) {
+        super(context, android.R.layout.simple_dropdown_item_1line, null);
+        mContentResolver = context.getContentResolver();
+    }
+
+    @Override
+    public final String convertToString(Cursor cursor) {
+        return makeDisplayString(cursor);
+    }
+
+    private final String makeDisplayString(Cursor cursor) {
+        String name = cursor.getString(NAME_INDEX);
+        String address = cursor.getString(DATA_INDEX);
+
+        return new Rfc822Token(name, address, null).toString();
+    }
+
+    @Override
+    public final void bindView(View view, Context context, Cursor cursor) {
+        ((TextView) view).setText(makeDisplayString(cursor));
+    }
+
+    @Override
+    public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
+        String filter = constraint == null ? "" : constraint.toString();
+        Uri uri = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, Uri.encode(filter));
+        return mContentResolver.query(uri, PROJECTION, null, null, SORT_ORDER);
+    }
+}
diff --git a/src/com/android/calendar/Event.java b/src/com/android/calendar/Event.java
index c15e5b5..956a0f6 100644
--- a/src/com/android/calendar/Event.java
+++ b/src/com/android/calendar/Event.java
@@ -23,6 +23,7 @@
 import android.os.Debug;
 import android.preference.PreferenceManager;
 import android.provider.Calendar.Attendees;
+import android.provider.Calendar.Events;
 import android.provider.Calendar.Instances;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
@@ -56,6 +57,8 @@
             Instances.RRULE,                 // 14
             Instances.RDATE,                 // 15
             Instances.SELF_ATTENDEE_STATUS,  // 16
+            Events.ORGANIZER,                // 17
+            Events.GUESTS_CAN_MODIFY,        // 18
     };
 
     // The indices for the projection array above.
@@ -75,12 +78,16 @@
     private static final int PROJECTION_RRULE_INDEX = 14;
     private static final int PROJECTION_RDATE_INDEX = 15;
     private static final int PROJECTION_SELF_ATTENDEE_STATUS_INDEX = 16;
+    private static final int PROJECTION_ORGANIZER_INDEX = 17;
+    private static final int PROJECTION_GUESTS_CAN_INVITE_OTHERS_INDEX = 18;
 
     public long id;
     public int color;
     public CharSequence title;
     public CharSequence location;
     public boolean allDay;
+    public String organizer;
+    public boolean guestsCanModify;
 
     public int startDay;       // start Julian day
     public int endDay;         // end Julian day
@@ -113,7 +120,8 @@
     private static final int MIDNIGHT_IN_MINUTES = 24 * 60;
 
     @Override
-    public final Object clone() {
+    public final Object clone() throws CloneNotSupportedException {
+        super.clone();
         Event e = new Event();
 
         e.title = title;
@@ -129,6 +137,8 @@
         e.hasAlarm = hasAlarm;
         e.isRepeating = isRepeating;
         e.selfAttendeeStatus = selfAttendeeStatus;
+        e.organizer = organizer;
+        e.guestsCanModify = guestsCanModify;
 
         return e;
     }
@@ -148,6 +158,8 @@
         dest.hasAlarm = hasAlarm;
         dest.isRepeating = isRepeating;
         dest.selfAttendeeStatus = selfAttendeeStatus;
+        dest.organizer = organizer;
+        dest.guestsCanModify = guestsCanModify;
     }
 
     public static final Event newInstance() {
@@ -195,6 +207,9 @@
         if (allDay && !e.allDay) return -1;
         if (!allDay && e.allDay) return 1;
 
+        if (guestsCanModify && !e.guestsCanModify) return -1;
+        if (!guestsCanModify && e.guestsCanModify) return 1;
+
         // If two events have the same time range, then sort them in
         // alphabetical order based on their titles.
         int cmp = compareStrings(title, e.title);
@@ -209,6 +224,11 @@
         if (cmp != 0) {
             return cmp;
         }
+
+        cmp = compareStrings(organizer, e.organizer);
+        if (cmp != 0) {
+            return cmp;
+        }
         return 0;
     }
 
@@ -315,6 +335,9 @@
                 e.title = c.getString(PROJECTION_TITLE_INDEX);
                 e.location = c.getString(PROJECTION_LOCATION_INDEX);
                 e.allDay = c.getInt(PROJECTION_ALL_DAY_INDEX) != 0;
+                e.organizer = c.getString(PROJECTION_ORGANIZER_INDEX);
+                e.guestsCanModify = c.getInt(PROJECTION_GUESTS_CAN_INVITE_OTHERS_INDEX) != 0;
+
                 String timezone = c.getString(PROJECTION_TIMEZONE_INDEX);
 
                 if (e.title == null || e.title.length() == 0) {
@@ -537,6 +560,8 @@
         Log.e("Cal", "+    endDay = " + endDay);
         Log.e("Cal", "+ startTime = " + startTime);
         Log.e("Cal", "+   endTime = " + endTime);
+        Log.e("Cal", "+ organizer = " + organizer);
+        Log.e("Cal", "+  guestwrt = " + guestsCanModify);
     }
 
     public final boolean intersects(int julianDay, int startMinute,
diff --git a/src/com/android/calendar/EventInfoActivity.java b/src/com/android/calendar/EventInfoActivity.java
index 9be1900..1abcb0b 100644
--- a/src/com/android/calendar/EventInfoActivity.java
+++ b/src/com/android/calendar/EventInfoActivity.java
@@ -18,36 +18,61 @@
 
 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.ContactsContract;
 import android.provider.Calendar.Attendees;
 import android.provider.Calendar.Calendars;
 import android.provider.Calendar.Events;
 import android.provider.Calendar.Reminders;
+import android.provider.ContactsContract.CommonDataKinds;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.QuickContact;
+import android.provider.ContactsContract.Intents;
+import android.provider.ContactsContract.Presence;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.text.TextUtils;
 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.OnTouchListener;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
+import android.widget.QuickContactBadge;
 import android.widget.ImageButton;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.Spinner;
 import android.widget.TextView;
@@ -55,11 +80,16 @@
 
 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,
         AdapterView.OnItemSelectedListener {
+    public static final boolean DEBUG = false;
+
+    public static final String TAG = "EventInfoActivity";
+
     private static final int MAX_REMINDERS = 5;
 
     /**
@@ -83,6 +113,11 @@
         Events.HAS_ALARM,            // 10
         Events.ACCESS_LEVEL,         // 11
         Events.COLOR,                // 12
+        Events.HAS_ATTENDEE_DATA,    // 13
+        Events.GUESTS_CAN_MODIFY,    // 14
+        // TODO Events.GUESTS_CAN_INVITE_OTHERS has not been implemented in calendar provider
+        Events.GUESTS_CAN_INVITE_OTHERS, // 15
+        Events.ORGANIZER,            // 16
     };
     private static final int EVENT_INDEX_ID = 0;
     private static final int EVENT_INDEX_TITLE = 1;
@@ -96,22 +131,37 @@
     private static final int EVENT_INDEX_HAS_ALARM = 10;
     private static final int EVENT_INDEX_ACCESS_LEVEL = 11;
     private static final int EVENT_INDEX_COLOR = 12;
+    private static final int EVENT_INDEX_HAS_ATTENDEE_DATA = 13;
+    private static final int EVENT_INDEX_GUESTS_CAN_MODIFY = 14;
+    private static final int EVENT_INDEX_CAN_INVITE_OTHERS = 15;
+    private static final int EVENT_INDEX_ORGANIZER = 16;
 
     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_ID = 0;
-    private static final int ATTENDEES_INDEX_RELATIONSHIP = 1;
-    private static final int ATTENDEES_INDEX_STATUS = 2;
+    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 ATTENDEES_SORT_ORDER = Attendees.ATTENDEE_NAME + " ASC, "
+            + Attendees.ATTENDEE_EMAIL + " ASC";
+
     static final String[] CALENDARS_PROJECTION = new String[] {
-        Calendars._ID,          // 0
-        Calendars.DISPLAY_NAME, // 1
+        Calendars._ID,           // 0
+        Calendars.DISPLAY_NAME,  // 1
+        Calendars.OWNER_ACCOUNT, // 2
     };
     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[] {
@@ -122,6 +172,7 @@
     private static final String REMINDERS_WHERE = Reminders.EVENT_ID + "=%d AND (" +
             Reminders.METHOD + "=" + Reminders.METHOD_ALERT + " OR " + Reminders.METHOD + "=" +
             Reminders.METHOD_DEFAULT + ")";
+    private static final String REMINDERS_SORT = Reminders.MINUTES;
 
     private static final int MENU_GROUP_REMINDER = 1;
     private static final int MENU_GROUP_EDIT = 2;
@@ -140,6 +191,8 @@
     };
 
     private LinearLayout mRemindersContainer;
+    private LinearLayout mOrganizerContainer;
+    private TextView mOrganizerView;
 
     private Uri mUri;
     private long mEventId;
@@ -149,8 +202,16 @@
 
     private long mStartMillis;
     private long mEndMillis;
-    private int mVisibility = Calendars.NO_ACCESS;
-    private int mRelationship = Attendees.RELATIONSHIP_ORGANIZER;
+
+    private boolean mHasAttendeeData;
+    private boolean mIsOrganizer;
+    private long mCalendarOwnerAttendeeId = -1;
+    private String mCalendarOwnerAccount;
+    private boolean mCanModifyCalendar;
+    private boolean mIsBusyFreeCalendar;
+    private boolean mCanModifyEvent;
+    private int mNumOfAttendees;
+    private String mOrganizer;
 
     private ArrayList<Integer> mOriginalMinutes = new ArrayList<Integer>();
     private ArrayList<LinearLayout> mReminderItems = new ArrayList<LinearLayout>(0);
@@ -163,9 +224,41 @@
 
     private int mResponseOffset;
     private int mOriginalAttendeeResponse;
+    private int mAttendeeResponseFromIntent = ATTENDEE_NO_RESPONSE;
     private boolean mIsRepeating;
 
     private Pattern mWildcardPattern = Pattern.compile("^.*$");
+    private LayoutInflater mLayoutInflater;
+    private LinearLayout mReminderAdder;
+
+    // TODO This can be removed when the contacts content provider doesn't return duplicates
+    private int mUpdateCounts;
+    private static class ViewHolder {
+        QuickContactBadge badge;
+        ImageView presence;
+        int updateCounts;
+    }
+    private HashMap<String, ViewHolder> mViewHolders = new HashMap<String, ViewHolder>();
+    private PresenceQueryHandler mPresenceQueryHandler;
+
+    private static final Uri CONTACT_DATA_WITH_PRESENCE_URI = Data.CONTENT_URI;
+
+    int PRESENCE_PROJECTION_CONTACT_ID_INDEX = 0;
+    int PRESENCE_PROJECTION_PRESENCE_INDEX = 1;
+    int PRESENCE_PROJECTION_EMAIL_INDEX = 2;
+    int PRESENCE_PROJECTION_PHOTO_ID_INDEX = 3;
+
+    private static final String[] PRESENCE_PROJECTION = new String[] {
+        Email.CONTACT_ID,           // 0
+        Email.CONTACT_PRESENCE,     // 1
+        Email.DATA,                 // 2
+        Email.PHOTO_ID,             // 3
+    };
+
+    ArrayList<Attendee> mAcceptedAttendees = new ArrayList<Attendee>();
+    ArrayList<Attendee> mDeclinedAttendees = new ArrayList<Attendee>();
+    ArrayList<Attendee> mTentativeAttendees = new ArrayList<Attendee>();
+    private int mColor;
 
     // This is called when one of the "remove reminder" buttons is selected.
     public void onClick(View v) {
@@ -175,33 +268,33 @@
         mReminderItems.remove(reminderItem);
         updateRemindersVisibility();
     }
-    
-    public void onItemSelected(AdapterView parent, View v, int position, long id) {
+
+    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) {
+    public void onNothingSelected(AdapterView<?> parent) {
     }
 
     @Override
@@ -214,6 +307,7 @@
         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.
@@ -222,27 +316,41 @@
         }
 
         setContentView(R.layout.event_info_activity);
-
-        // Attendees cursor
-        Uri uri = Attendees.CONTENT_URI;
-        String where = String.format(ATTENDEES_WHERE, mEventId);
-        mAttendeesCursor = managedQuery(uri, ATTENDEES_PROJECTION, where, null);
-        initAttendeesCursor();
+        mPresenceQueryHandler = new PresenceQueryHandler(this, cr);
+        mLayoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mRemindersContainer = (LinearLayout) findViewById(R.id.reminders_container);
+        mOrganizerContainer = (LinearLayout) findViewById(R.id.organizer_container);
+        mOrganizerView = (TextView) findViewById(R.id.organizer);
 
         // Calendars cursor
-        uri = Calendars.CONTENT_URI;
-        where = String.format(CALENDARS_WHERE, mEventCursor.getLong(EVENT_INDEX_CALENDAR_ID));
+        Uri uri = Calendars.CONTENT_URI;
+        String where = String.format(CALENDARS_WHERE, mEventCursor.getLong(EVENT_INDEX_CALENDAR_ID));
         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));
+        mCalendarOwnerAccount = "";
+        if (mCalendarsCursor != null) {
+            mCalendarsCursor.moveToFirst();
+            mCalendarOwnerAccount = mCalendarsCursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
         }
+        String eventOrganizer = mEventCursor.getString(EVENT_INDEX_ORGANIZER);
+        mIsOrganizer = mCalendarOwnerAccount.equals(eventOrganizer);
+        mHasAttendeeData = mEventCursor.getInt(EVENT_INDEX_HAS_ATTENDEE_DATA) != 0;
+
+        updateView();
+
+        // Attendees cursor
+        uri = Attendees.CONTENT_URI;
+        where = String.format(ATTENDEES_WHERE, mEventId);
+        mAttendeesCursor = managedQuery(uri, ATTENDEES_PROJECTION, where, ATTENDEES_SORT_ORDER);
+        initAttendeesCursor();
+
+        mOrganizer = eventOrganizer;
+        mCanModifyCalendar =
+                mEventCursor.getInt(EVENT_INDEX_ACCESS_LEVEL) >= Calendars.CONTRIBUTOR_ACCESS;
+        mIsBusyFreeCalendar =
+                mEventCursor.getInt(EVENT_INDEX_ACCESS_LEVEL) == Calendars.FREEBUSY_ACCESS;
+
+        mCanModifyEvent = mCanModifyCalendar
+                && (mIsOrganizer || (mEventCursor.getInt(EVENT_INDEX_GUESTS_CAN_MODIFY) != 0));
 
         // Initialize the reminder values array.
         Resources r = getResources();
@@ -261,14 +369,13 @@
                 prefs.getString(CalendarPreferenceActivity.KEY_DEFAULT_REMINDER, "0");
         mDefaultReminderMinutes = Integer.parseInt(durationString);
 
-        mRemindersContainer = (LinearLayout) findViewById(R.id.reminder_items_container);
-
         // Reminders cursor
         boolean hasAlarm = mEventCursor.getInt(EVENT_INDEX_HAS_ALARM) != 0;
         if (hasAlarm) {
             uri = Reminders.CONTENT_URI;
             where = String.format(REMINDERS_WHERE, mEventId);
-            Cursor reminderCursor = cr.query(uri, REMINDERS_PROJECTION, where, null, null);
+            Cursor reminderCursor = cr.query(uri, REMINDERS_PROJECTION, where, null,
+                    REMINDERS_SORT);
             try {
                 // First pass: collect all the custom reminder minutes (e.g.,
                 // a reminder of 8 minutes) into a global list.
@@ -276,7 +383,7 @@
                     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()) {
@@ -290,17 +397,17 @@
             }
         }
 
-        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);
+        };
+        ImageButton reminderAddButton = (ImageButton) findViewById(R.id.reminder_add);
+        reminderAddButton.setOnClickListener(addReminderOnClickListener);
+
+        mReminderAdder = (LinearLayout) findViewById(R.id.reminder_adder);
+        updateRemindersVisibility();
 
         mDeleteEventHelper = new DeleteEventHelper(this, true /* exit when done */);
         mEditResponseHelper = new EditResponseHelper(this);
@@ -314,8 +421,18 @@
             finish();
             return;
         }
-        initAttendeesCursor();
         initCalendarsCursor();
+        updateResponse();
+        updateTitle();
+    }
+
+    private void updateTitle() {
+        Resources res = getResources();
+        if (mCanModifyCalendar && !mIsOrganizer) {
+            setTitle(res.getString(R.string.event_info_title_invite));
+        } else {
+            setTitle(res.getString(R.string.event_info_title));
+        }
     }
 
     /**
@@ -328,19 +445,81 @@
             return true;
         }
         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() {
+        mOriginalAttendeeResponse = ATTENDEE_NO_RESPONSE;
+        mCalendarOwnerAttendeeId = -1;
+        mNumOfAttendees = 0;
         if (mAttendeesCursor != null) {
+            mNumOfAttendees = mAttendeesCursor.getCount();
             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);
+
+                    if (mAttendeesCursor.getInt(ATTENDEES_INDEX_RELATIONSHIP) ==
+                            Attendees.RELATIONSHIP_ORGANIZER) {
+                        // Overwrites the one from Event table if available
+                        if (name != null && name.length() > 0) {
+                            mOrganizer = name;
+                        } else if (email != null && email.length() > 0) {
+                            mOrganizer = email;
+                        }
+                    }
+
+                    if (mCalendarOwnerAttendeeId == -1 && mCalendarOwnerAccount.equals(email)) {
+                        mCalendarOwnerAttendeeId = mAttendeesCursor.getInt(ATTENDEES_INDEX_ID);
+                        mOriginalAttendeeResponse = mAttendeesCursor.getInt(ATTENDEES_INDEX_STATUS);
+                    } else {
+                        // Don't show your own status in the list because:
+                        //  1) it doesn't make sense for event without other guests.
+                        //  2) there's a spinner for that for events with guests.
+                        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();
             }
         }
+        // only show the organizer if we're not the organizer and if
+        // we have attendee data (might have been removed by the server
+        // for events with a lot of attendees).
+        if (!mIsOrganizer && mHasAttendeeData) {
+            mOrganizerContainer.setVisibility(View.VISIBLE);
+            mOrganizerView.setText(mOrganizer);
+        } else {
+            mOrganizerContainer.setVisibility(View.GONE);
+        }
     }
 
     private void initCalendarsCursor() {
@@ -358,8 +537,17 @@
         ContentResolver cr = getContentResolver();
         ArrayList<Integer> reminderMinutes = EditEvent.reminderItemsToMinutes(mReminderItems,
                 mReminderValues);
-        boolean changed = EditEvent.saveReminders(cr, mEventId, reminderMinutes, mOriginalMinutes,
+        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) {
+            Log.w(TAG, "Ignoring exception: ", e);
+        } catch (OperationApplicationException e) {
+            Log.w(TAG, "Ignoring exception: ", e);
+        }
+
         changed |= saveResponse(cr);
         if (changed) {
             Toast.makeText(this, R.string.saving_event, Toast.LENGTH_SHORT).show();
@@ -386,32 +574,22 @@
 
     @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 = canAddReminders();
+        menu.setGroupVisible(MENU_GROUP_REMINDER, canAddReminders);
+        menu.setGroupEnabled(MENU_GROUP_REMINDER, canAddReminders);
 
-        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);
-        } 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);
-        }
+        menu.setGroupVisible(MENU_GROUP_EDIT, mCanModifyEvent);
+        menu.setGroupEnabled(MENU_GROUP_EDIT, mCanModifyEvent);
+        menu.setGroupVisible(MENU_GROUP_DELETE, mCanModifyCalendar);
+        menu.setGroupEnabled(MENU_GROUP_DELETE, mCanModifyCalendar);
 
         return super.onPrepareOptionsMenu(menu);
     }
-    
+
+    private boolean canAddReminders() {
+        return !mIsBusyFreeCalendar && mReminderItems.size() < MAX_REMINDERS;
+    }
+
     private void addReminder() {
         // TODO: when adding a new reminder, make it different from the
         // last one in the list (if any).
@@ -452,17 +630,18 @@
     }
 
     private void updateRemindersVisibility() {
-        if (mReminderItems.size() == 0) {
+        if (mIsBusyFreeCalendar) {
             mRemindersContainer.setVisibility(View.GONE);
         } else {
             mRemindersContainer.setVisibility(View.VISIBLE);
+            mReminderAdder.setVisibility(canAddReminders() ? View.VISIBLE : View.GONE);
         }
     }
 
     /**
      * 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
      */
@@ -483,10 +662,9 @@
             return false;
         }
 
-        long attendeeId = mAttendeesCursor.getInt(ATTENDEES_INDEX_ID);
         if (!mIsRepeating) {
             // This is a non-repeating event
-            updateResponse(cr, mEventId, attendeeId, status);
+            updateResponse(cr, mEventId, mCalendarOwnerAttendeeId, status);
             return true;
         }
 
@@ -496,30 +674,33 @@
             case -1:
                 return false;
             case UPDATE_SINGLE:
-                createExceptionResponse(cr, mEventId, attendeeId, status);
+                createExceptionResponse(cr, mEventId, mCalendarOwnerAttendeeId, status);
                 return true;
             case UPDATE_ALL:
-                updateResponse(cr, mEventId, attendeeId, status);
+                updateResponse(cr, mEventId, mCalendarOwnerAttendeeId, status);
                 return true;
             default:
-                Log.e("Calendar", "Unexpected choice for updating invitation response");
+                Log.e(TAG, "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
+        // Update the attendee status in the attendees table.  the provider
+        // takes care of updating the self attendance status.
         ContentValues values = new ContentValues();
 
-        // Will need to add email when MULTIPLE_ATTENDEES_PER_EVENT supported.
+        if (!TextUtils.isEmpty(mCalendarOwnerAccount)) {
+            values.put(Attendees.ATTENDEE_EMAIL, mCalendarOwnerAccount);
+        }
         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.
@@ -532,13 +713,13 @@
         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);
@@ -550,9 +731,9 @@
             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
-            Uri newUri = cr.insert(Events.CONTENT_URI, values);
+            cr.insert(Events.CONTENT_URI, values);
         } finally {
             cursor.close();
         }
@@ -586,11 +767,10 @@
         if (mEventCursor == null) {
             return;
         }
-        Resources res = getResources();
-        ContentResolver cr = getContentResolver();
 
         String eventName = mEventCursor.getString(EVENT_INDEX_TITLE);
         if (eventName == null || eventName.length() == 0) {
+            Resources res = getResources();
             eventName = res.getString(R.string.no_title_label);
         }
 
@@ -600,17 +780,17 @@
         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(color);
+        calBackground.setBackgroundColor(mColor);
 
         TextView title = (TextView) findViewById(R.id.title);
-        title.setTextColor(color);
-        
-        View divider = (View) findViewById(R.id.divider);
-        divider.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_IN);
-        
+        title.setTextColor(mColor);
+
+        View divider = findViewById(R.id.divider);
+        divider.getBackground().setColorFilter(mColor, PorterDuff.Mode.SRC_IN);
+
         // What
         if (eventName != null) {
             setTextCommon(R.id.title, eventName);
@@ -670,11 +850,21 @@
         if (location == null || location.length() == 0) {
             setVisibilityCommon(R.id.where, View.GONE);
         } else {
-            TextView textView = (TextView) findViewById(R.id.where);
+            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;
+                            }
+                        }
+                    });
             }
         }
 
@@ -687,20 +877,149 @@
 
         // Calendar
         if (mCalendarsCursor != null) {
-            mCalendarsCursor.moveToFirst();
             String calendarName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
             setTextCommon(R.id.calendar, calendarName);
         } 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();
+        ++mUpdateCounts;
+        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.badge).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(Email.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.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.badge = (QuickContactBadge) v.findViewById(R.id.badge);
+            vh.badge.assignContactFromEmail(attendee.mEmail, true);
+            vh.presence = (ImageView) v.findViewById(R.id.presence);
+            mViewHolders.put(attendee.mEmail, vh);
+
+            if (i == 0) {
+                selection.append('?');
+            } else {
+                selection.append(", ?");
+            }
+
+            attendeeList.addView(v);
+        }
+        selection.append(')');
+
+        mPresenceQueryHandler.startQuery(mUpdateCounts, attendees, CONTACT_DATA_WITH_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;
+        }
+
+        @Override
+        protected void onQueryComplete(int queryIndex, Object cookie, Cursor cursor) {
+            if (cursor == null) {
+                if (DEBUG) {
+                    Log.e(TAG, "onQueryComplete: cursor == null");
+                }
+                return;
+            }
+
+            try {
+                cursor.moveToPosition(-1);
+                while (cursor.moveToNext()) {
+                    String email = cursor.getString(PRESENCE_PROJECTION_EMAIL_INDEX);
+                    int contactId = cursor.getInt(PRESENCE_PROJECTION_CONTACT_ID_INDEX);
+                    ViewHolder vh = mViewHolders.get(email);
+                    int photoId = cursor.getInt(PRESENCE_PROJECTION_PHOTO_ID_INDEX);
+                    if (DEBUG) {
+                        Log.e(TAG, "onQueryComplete Id: " + contactId + " PhotoId: " + photoId
+                                + " Email: " + email);
+                    }
+                    if (vh == null) {
+                        continue;
+                    }
+                    ImageView presenceView = vh.presence;
+                    if (presenceView != null) {
+                        int status = cursor.getInt(PRESENCE_PROJECTION_PRESENCE_INDEX);
+                        presenceView.setImageResource(Presence.getPresenceIconResourceId(status));
+                        presenceView.setVisibility(View.VISIBLE);
+                    }
+
+                    if (photoId > 0 && vh.updateCounts < queryIndex) {
+                        vh.updateCounts = queryIndex;
+                        Uri personUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
+                        ContactsAsyncHelper.updateImageViewWithContactPhotoAsync(mContext, vh.badge,
+                                personUri, R.drawable.ic_contact_picture);
+                    }
+                }
+            } finally {
+                cursor.close();
+            }
+        }
     }
 
     void updateResponse() {
-        if (mVisibility < Calendars.CONTRIBUTOR_ACCESS ||
-                mRelationship != Attendees.RELATIONSHIP_ATTENDEE) {
+        // we only let the user accept/reject/etc. a meeting if:
+        // a) you can edit the event's containing calendar AND
+        // b) you're not the organizer and only attendee
+        // (if the attendee data has been hidden, the visible number of attendees
+        // will be 1 -- the calendar owner's).
+        // (there are more cases involved to be 100% accurate, such as
+        // paying attention to whether or not an attendee status was
+        // included in the feed, but we're currently omitting those corner cases
+        // for simplicity).
+        if (!mCanModifyCalendar || (mHasAttendeeData && mIsOrganizer && mNumOfAttendees <= 1)) {
             setVisibilityCommon(R.id.response_container, View.GONE);
             return;
         }
@@ -709,10 +1028,6 @@
 
         Spinner spinner = (Spinner) findViewById(R.id.response_value);
 
-        mOriginalAttendeeResponse = ATTENDEE_NO_RESPONSE;
-        if (mAttendeesCursor != null) {
-            mOriginalAttendeeResponse = mAttendeesCursor.getInt(ATTENDEES_INDEX_STATUS);
-        }
         mResponseOffset = 0;
 
         /* If the user has previously responded to this event
@@ -733,7 +1048,12 @@
             spinner.setAdapter(adapter);
         }
 
-        int index = findResponseIndexFor(mOriginalAttendeeResponse);
+        int index;
+        if (mAttendeeResponseFromIntent != ATTENDEE_NO_RESPONSE) {
+            index = findResponseIndexFor(mAttendeeResponseFromIntent);
+        } else {
+            index = findResponseIndexFor(mOriginalAttendeeResponse);
+        }
         spinner.setSelection(index + mResponseOffset);
         spinner.setOnItemSelectedListener(this);
     }
@@ -752,4 +1072,39 @@
         }
         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) {
+        // First perform lookup query to find existing contact
+        final ContentResolver resolver = getContentResolver();
+        final String address = attendee.mEmail;
+        final Uri dataUri = Uri.withAppendedPath(CommonDataKinds.Email.CONTENT_FILTER_URI,
+                Uri.encode(address));
+        final Uri lookupUri = ContactsContract.Data.getContactLookupUri(resolver, dataUri);
+
+        if (lookupUri != null) {
+            // Found matching contact, trigger QuickContact
+            QuickContact.showQuickContact(this, rect, lookupUri, QuickContact.MODE_MEDIUM, null);
+        } else {
+            // No matching contact, ask user to create one
+            final Uri mailUri = Uri.fromParts("mailto", address, null);
+            final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, mailUri);
+
+            // Pass along full E-mail string for possible create dialog
+            Rfc822Token sender = new Rfc822Token(attendee.mName, attendee.mEmail, null);
+            intent.putExtra(Intents.EXTRA_CREATE_DESCRIPTION, sender.toString());
+
+            // Only provide personal name hint if we have one
+            final String senderPersonal = attendee.mName;
+            if (!TextUtils.isEmpty(senderPersonal)) {
+                intent.putExtra(Intents.Insert.NAME, senderPersonal);
+            }
+
+            startActivity(intent);
+        }
+    }
 }
diff --git a/src/com/android/calendar/GoogleCalendarUriIntentFilter.java b/src/com/android/calendar/GoogleCalendarUriIntentFilter.java
new file mode 100644
index 0000000..502243a
--- /dev/null
+++ b/src/com/android/calendar/GoogleCalendarUriIntentFilter.java
@@ -0,0 +1,118 @@
+/*
+**
+** Copyright 2009, 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,
+** See the License for the specific language governing permissions and
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** limitations under the License.
+*/
+
+package com.android.calendar;
+
+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 static android.provider.Calendar.AttendeesColumns.ATTENDEE_STATUS_ACCEPTED;
+import static android.provider.Calendar.AttendeesColumns.ATTENDEE_STATUS_DECLINED;
+import static android.provider.Calendar.AttendeesColumns.ATTENDEE_STATUS_NONE;
+import static android.provider.Calendar.AttendeesColumns.ATTENDEE_STATUS_TENTATIVE;
+
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Calendar.Events;
+
+public class GoogleCalendarUriIntentFilter extends Activity {
+    private static final int EVENT_INDEX_ID = 0;
+    private static final int EVENT_INDEX_START = 1;
+    private static final int EVENT_INDEX_END = 2;
+
+    private static final String[] EVENT_PROJECTION = new String[] {
+        Events._ID,      // 0
+        Events.DTSTART,  // 1
+        Events.DTEND,    // 2
+    };
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        Intent intent = getIntent();
+        if (intent != null) {
+            Uri uri = intent.getData();
+            if (uri != null) {
+                String eid = uri.getQueryParameter("eid");
+                if (eid != null) {
+                    ContentResolver cr = getContentResolver();
+                    String selection = Events.HTML_URI + " LIKE \"%eid=" + eid + "%\"";
+
+                    Cursor eventCursor = managedQuery(Events.CONTENT_URI, EVENT_PROJECTION,
+                            selection, null);
+
+                    // TODO what to do when there's more than one match
+                    if (eventCursor != null && eventCursor.getCount() > 0) {
+                        // Get info from Cursor
+                        eventCursor.moveToFirst();
+                        int eventId = eventCursor.getInt(EVENT_INDEX_ID);
+                        long startMillis = eventCursor.getLong(EVENT_INDEX_START);
+                        long endMillis = eventCursor.getLong(EVENT_INDEX_END);
+
+                        // Pick up attendee status action from uri clicked
+                        int attendeeStatus = ATTENDEE_STATUS_NONE;
+                        if ("RESPOND".equals(uri.getQueryParameter("action"))) {
+                            try {
+                                switch (Integer.parseInt(uri.getQueryParameter("rst"))) {
+                                case 1: // Yes
+                                    attendeeStatus = ATTENDEE_STATUS_ACCEPTED;
+                                    break;
+                                case 2: // No
+                                    attendeeStatus = ATTENDEE_STATUS_DECLINED;
+                                    break;
+                                case 3: // Maybe
+                                    attendeeStatus = ATTENDEE_STATUS_TENTATIVE;
+                                    break;
+                                }
+                            } catch (NumberFormatException e) {
+                                // ignore this error as if the response code
+                                // wasn't in the uri.
+                            }
+                        }
+
+                        // Send intent to calendar app
+                        Uri calendarUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId);
+                        intent = new Intent(Intent.ACTION_VIEW, calendarUri);
+                        intent.putExtra(EVENT_BEGIN_TIME, startMillis);
+                        intent.putExtra(EVENT_END_TIME, endMillis);
+                        if (attendeeStatus != ATTENDEE_STATUS_NONE) {
+                            intent.putExtra(ATTENDEE_STATUS, attendeeStatus);
+                        }
+                        startActivity(intent);
+                        finish();
+                        return;
+                    }
+                }
+            }
+
+            // Can't handle the intent. Pass it on to the next Activity.
+            try {
+                startNextMatchingActivity(intent);
+            } catch (ActivityNotFoundException ex) {
+                // no browser installed? Just drop it.
+            }
+        }
+        finish();
+    }
+}
diff --git a/src/com/android/calendar/IcsImportActivity.java b/src/com/android/calendar/IcsImportActivity.java
index c4f5fde..c5a125d 100644
--- a/src/com/android/calendar/IcsImportActivity.java
+++ b/src/com/android/calendar/IcsImportActivity.java
@@ -60,11 +60,9 @@
         }
     }
 
-    private View mView;
     private Button mImportButton;
     private Button mCancelButton;
     private Spinner mCalendars;
-    private ImageView mCalendarIcon;
     private TextView mNumEvents;
 
     private ICalendar.Component mCalendar = null;
@@ -86,9 +84,7 @@
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         setContentView(R.layout.ics_import_activity);
-        mView = findViewById(R.id.import_ics);
 
-        mCalendarIcon = (ImageView) findViewById(R.id.calendar_icon);
         mCalendars = (Spinner) findViewById(R.id.calendars);
         populateCalendars();
 
diff --git a/src/com/android/calendar/LaunchActivity.java b/src/com/android/calendar/LaunchActivity.java
index 1f053d7..36d6ab6 100644
--- a/src/com/android/calendar/LaunchActivity.java
+++ b/src/com/android/calendar/LaunchActivity.java
@@ -16,9 +16,12 @@
 
 package com.android.calendar;
 
-import com.google.android.googlelogin.GoogleLoginServiceConstants;
-import com.google.android.googlelogin.GoogleLoginServiceHelper;
-
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
 import android.app.Activity;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -27,11 +30,12 @@
 import android.preference.PreferenceManager;
 import android.provider.Gmail;
 
+import com.google.android.googlelogin.GoogleLoginServiceConstants;
+
+import java.io.IOException;
+
 public class LaunchActivity extends Activity {
     static final String KEY_DETAIL_VIEW = "DETAIL_VIEW";
-
-    // An arbitrary constant to pass to the GoogleLoginHelperService
-    private static final int GET_ACCOUNT_REQUEST = 1;
     private Bundle mExtras;
 
     @Override
@@ -42,26 +46,39 @@
         // Our UI is not something intended for the user to see.  We just
         // stick around until we can figure out what to do next based on
         // the current state of the system.
-        setVisible(false);
+        // TODO: Removed until framework is fixed in b/2008662
+        // setVisible(false);
 
         // Only try looking for an account if this is the first launch.
         if (icicle == null) {
             // This will request a Gmail account and if none are present, it will
             // invoke SetupWizard to login or create one. The result is returned
-            // through onActivityResult().
+            // via the Future2Callback.
             Bundle bundle = new Bundle();
             bundle.putCharSequence("optional_message", getText(R.string.calendar_plug));
-            GoogleLoginServiceHelper.getCredentials(
-                    this,
-                    GET_ACCOUNT_REQUEST,
-                    bundle,
-                    GoogleLoginServiceConstants.PREFER_HOSTED,
-                    Gmail.GMAIL_AUTH_SERVICE,
-                    true);
+            AccountManager.get(this).getAuthTokenByFeatures(
+                    GoogleLoginServiceConstants.ACCOUNT_TYPE, Gmail.GMAIL_AUTH_SERVICE,
+                    new String[]{GoogleLoginServiceConstants.FEATURE_LEGACY_HOSTED_OR_GOOGLE}, this,
+                    bundle, null /* loginOptions */, new AccountManagerCallback<Bundle>() {
+                public void run(AccountManagerFuture<Bundle> future) {
+                    try {
+                        Bundle result = future.getResult();
+                        onAccountsLoaded(new Account(
+                                result.getString(GoogleLoginServiceConstants.AUTH_ACCOUNT_KEY),
+                                result.getString(AccountManager.KEY_ACCOUNT_TYPE)));
+                    } catch (OperationCanceledException e) {
+                        finish();
+                    } catch (IOException e) {
+                        finish();
+                    } catch (AuthenticatorException e) {
+                        finish();
+                    }
+                }
+            }, null /* handler */);
         }
     }
 
-    private void onAccountsLoaded(String account) {
+    private void onAccountsLoaded(Account account) {
         // Get the data for from this intent, if any
         Intent myIntent = getIntent();
         Uri myData = myIntent.getData();
@@ -86,26 +103,8 @@
                 CalendarPreferenceActivity.DEFAULT_START_VIEW);
 
         intent.setClassName(this, startActivity);
+        intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
         startActivity(intent);
         finish();
     }
-
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
-        super.onActivityResult(requestCode, resultCode, intent);
-        if (requestCode == GET_ACCOUNT_REQUEST) {
-            if (resultCode == RESULT_OK) {
-                if (intent != null) {
-                    Bundle extras = intent.getExtras();
-                    if (extras != null) {
-                        final String account;
-                        account = extras.getString(GoogleLoginServiceConstants.AUTH_ACCOUNT_KEY);
-                        onAccountsLoaded(account);
-                    }
-                }
-            } else {
-                finish();
-            }
-        }
-    }
 }
diff --git a/src/com/android/calendar/MenuHelper.java b/src/com/android/calendar/MenuHelper.java
index f23cbf9..6ed1512 100644
--- a/src/com/android/calendar/MenuHelper.java
+++ b/src/com/android/calendar/MenuHelper.java
@@ -139,23 +139,19 @@
             nav.goToToday();
             return true;
         case MENU_PREFERENCES:
-            switchTo(activity, CalendarPreferenceActivity.class.getName(), nav.getSelectedTime());
+            Utils.startActivity(activity, CalendarPreferenceActivity.class.getName(), nav.getSelectedTime());
             return true;
         case MENU_AGENDA:
-            switchTo(activity, AgendaActivity.class.getName(), nav.getSelectedTime());
-            activity.finish();
+            Utils.startActivity(activity, AgendaActivity.class.getName(), nav.getSelectedTime());
             return true;
         case MENU_DAY:
-            switchTo(activity, DayActivity.class.getName(), nav.getSelectedTime());
-            activity.finish();
+            Utils.startActivity(activity, DayActivity.class.getName(), nav.getSelectedTime());
             return true;
         case MENU_WEEK:
-            switchTo(activity, WeekActivity.class.getName(), nav.getSelectedTime());
-            activity.finish();
+            Utils.startActivity(activity, WeekActivity.class.getName(), nav.getSelectedTime());
             return true;
         case MENU_MONTH:
-            switchTo(activity, MonthActivity.class.getName(), nav.getSelectedTime());
-            activity.finish();
+            Utils.startActivity(activity, MonthActivity.class.getName(), nav.getSelectedTime());
             return true;
         case MENU_EVENT_CREATE: {
             long startMillis = nav.getSelectedTime();
@@ -171,11 +167,4 @@
         }
         return false;
     }
-    
-    /* package */ static void switchTo(Activity activity, String className, long startMillis) {
-        Intent intent = new Intent(Intent.ACTION_VIEW);
-        intent.setClassName(activity, className);
-        intent.putExtra(EVENT_BEGIN_TIME, startMillis);
-        activity.startActivity(intent);
-    }
 }
diff --git a/src/com/android/calendar/MonthActivity.java b/src/com/android/calendar/MonthActivity.java
index 89b07ec..62f8602 100644
--- a/src/com/android/calendar/MonthActivity.java
+++ b/src/com/android/calendar/MonthActivity.java
@@ -17,7 +17,6 @@
 package com.android.calendar;
 
 import static android.provider.Calendar.EVENT_BEGIN_TIME;
-import dalvik.system.VMRuntime;
 
 import android.app.Activity;
 import android.content.BroadcastReceiver;
@@ -45,6 +44,8 @@
 import android.widget.ViewSwitcher;
 import android.widget.Gallery.LayoutParams;
 
+import dalvik.system.VMRuntime;
+
 import java.util.Calendar;
 
 public class MonthActivity extends Activity implements ViewSwitcher.ViewFactory,
@@ -83,7 +84,7 @@
     }
 
     /* Navigator interface methods */
-    public void goTo(Time time) {
+    public void goTo(Time time, boolean animate) {
         TextView title = (TextView) findViewById(R.id.title);
         title.setText(Utils.formatMonthYear(time));
 
@@ -96,14 +97,16 @@
         // two adjacent months.
         // This is faster than calling getSelectedTime() because we avoid
         // a call to Time#normalize().
-        int currentMonth = currentTime.month + currentTime.year * 12;
-        int nextMonth = time.month + time.year * 12;
-        if (nextMonth < currentMonth) {
-            mSwitcher.setInAnimation(mInAnimationPast);
-            mSwitcher.setOutAnimation(mOutAnimationPast);
-        } else {
-            mSwitcher.setInAnimation(mInAnimationFuture);
-            mSwitcher.setOutAnimation(mOutAnimationFuture);
+        if (animate) {
+            int currentMonth = currentTime.month + currentTime.year * 12;
+            int nextMonth = time.month + time.year * 12;
+            if (nextMonth < currentMonth) {
+                mSwitcher.setInAnimation(mInAnimationPast);
+                mSwitcher.setOutAnimation(mOutAnimationPast);
+            } else {
+                mSwitcher.setInAnimation(mInAnimationFuture);
+                mSwitcher.setOutAnimation(mOutAnimationFuture);
+            }
         }
 
         MonthView next = (MonthView) mSwitcher.getNextView();
@@ -119,6 +122,9 @@
     public void goToToday() {
         Time now = new Time();
         now.set(System.currentTimeMillis());
+        now.minute = 0;
+        now.second = 0;
+        now.normalize(false);
 
         TextView title = (TextView) findViewById(R.id.title);
         title.setText(Utils.formatMonthYear(now));
@@ -195,7 +201,7 @@
 
         // Eliminate extra GCs during startup by setting the initial heap size to 4MB.
         // TODO: We should restore the old heap size once the activity reaches the idle state
-        long oldHeapSize = VMRuntime.getRuntime().setMinimumHeapSize(INITIAL_HEAP_SIZE);
+        VMRuntime.getRuntime().setMinimumHeapSize(INITIAL_HEAP_SIZE);
 
         setContentView(R.layout.month_activity);
         mContentResolver = getContentResolver();
@@ -258,6 +264,16 @@
     }
 
     @Override
+    protected void onNewIntent(Intent intent) {
+        long timeMillis = Utils.timeFromIntentInMillis(intent);
+        if (timeMillis > 0) {
+            Time time = new Time();
+            time.set(timeMillis);
+            goTo(time, false);
+        }
+    }
+
+    @Override
     protected void onPause() {
         super.onPause();
         if (isFinishing()) {
@@ -271,6 +287,9 @@
         view = (MonthView) mSwitcher.getNextView();
         view.dismissPopup();
         mEventLoader.stopBackgroundThread();
+
+        // Record Month View as the (new) start view
+        Utils.setDefaultView(this, CalendarApplication.MONTH_VIEW_ID);
     }
 
     @Override
@@ -287,12 +306,6 @@
         view1.setDetailedView(str);
         view2.setDetailedView(str);
 
-        // Record Month View as the (new) start view
-        String activityString = CalendarApplication.ACTIVITY_NAMES[CalendarApplication.MONTH_VIEW_ID];
-        SharedPreferences.Editor editor = prefs.edit();
-        editor.putString(CalendarPreferenceActivity.KEY_START_VIEW, activityString);
-        editor.commit();
-
         // Register for Intent broadcasts
         IntentFilter filter = new IntentFilter();
 
@@ -312,16 +325,6 @@
     }
 
     @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_BACK:
-                finish();
-                return true;
-        }
-        return super.onKeyDown(keyCode, event);
-    }
-
-    @Override
     public boolean onPrepareOptionsMenu(Menu menu) {
         MenuHelper.onPrepareOptionsMenu(this, menu);
         return super.onPrepareOptionsMenu(menu);
diff --git a/src/com/android/calendar/MonthView.java b/src/com/android/calendar/MonthView.java
index f6db3b8..13f6abc 100644
--- a/src/com/android/calendar/MonthView.java
+++ b/src/com/android/calendar/MonthView.java
@@ -60,19 +60,20 @@
     private static final boolean PROFILE_LOAD_TIME = false;
     private static final boolean DEBUG_BUSYBITS = false;
 
-    private static final int WEEK_GAP = 0;
-    private static final int MONTH_DAY_GAP = 1;
-    private static final float HOUR_GAP = 0.5f;
+    private static float mScale = 0; // Used for supporting different screen densities
+    private static int WEEK_GAP = 0;
+    private static int MONTH_DAY_GAP = 1;
+    private static float HOUR_GAP = 0.5f;
 
-    private static final int MONTH_DAY_TEXT_SIZE = 20;
-    private static final int WEEK_BANNER_HEIGHT = 17;
-    private static final int WEEK_TEXT_SIZE = 15;
-    private static final int WEEK_TEXT_PADDING = 3;
-    private static final int BUSYBIT_WIDTH = 10;
-    private static final int BUSYBIT_RIGHT_MARGIN = 3;
-    private static final int BUSYBIT_TOP_BOTTOM_MARGIN = 7;
+    private static int MONTH_DAY_TEXT_SIZE = 20;
+    private static int WEEK_BANNER_HEIGHT = 17;
+    private static int WEEK_TEXT_SIZE = 15;
+    private static int WEEK_TEXT_PADDING = 3;
+    private static int BUSYBIT_WIDTH = 10;
+    private static int BUSYBIT_RIGHT_MARGIN = 3;
+    private static int BUSYBIT_TOP_BOTTOM_MARGIN = 7;
 
-    private static final int HORIZONTAL_FLING_THRESHOLD = 50;
+    private static int HORIZONTAL_FLING_THRESHOLD = 50;
 
     private int mCellHeight;
     private int mBorder;
@@ -196,6 +197,25 @@
 
     public MonthView(MonthActivity activity, Navigator navigator) {
         super(activity);
+        if (mScale == 0) {
+            mScale = getContext().getResources().getDisplayMetrics().density;
+           if (mScale != 1) {
+                    WEEK_GAP *= mScale;
+                    MONTH_DAY_GAP *= mScale;
+                    HOUR_GAP *= mScale;
+
+                    MONTH_DAY_TEXT_SIZE *= mScale;
+                    WEEK_BANNER_HEIGHT *= mScale;
+                    WEEK_TEXT_SIZE *= mScale;
+                    WEEK_TEXT_PADDING *= mScale;
+                    BUSYBIT_WIDTH *= mScale;
+                    BUSYBIT_RIGHT_MARGIN *= mScale;
+                    BUSYBIT_TOP_BOTTOM_MARGIN *= mScale;
+
+                    HORIZONTAL_FLING_THRESHOLD *= mScale;
+                }
+            }
+
         mEventLoader = activity.mEventLoader;
         mNavigator = navigator;
         mEventGeometry = new EventGeometry();
@@ -282,7 +302,7 @@
                     time.month -= 1;
                 }
                 time.normalize(true);
-                mParentActivity.goTo(time);
+                mParentActivity.goTo(time, true);
 
                 return true;
             }
@@ -358,7 +378,6 @@
                     int y = (int) e.getY();
                     long millis = getSelectedMillisFor(x, y);
                     Utils.startActivity(getContext(), mDetailedView, millis);
-                    mParentActivity.finish();
                 }
 
                 return true;
@@ -397,14 +416,12 @@
             switch (item.getItemId()) {
                 case MenuHelper.MENU_DAY: {
                     long startMillis = getSelectedTimeInMillis();
-                    MenuHelper.switchTo(mParentActivity, DayActivity.class.getName(), startMillis);
-                    mParentActivity.finish();
+                    Utils.startActivity(mParentActivity, DayActivity.class.getName(), startMillis);
                     break;
                 }
                 case MenuHelper.MENU_AGENDA: {
                     long startMillis = getSelectedTimeInMillis();
-                    MenuHelper.switchTo(mParentActivity, AgendaActivity.class.getName(), startMillis);
-                    mParentActivity.finish();
+                    Utils.startActivity(mParentActivity, AgendaActivity.class.getName(), startMillis);
                     break;
                 }
                 case MenuHelper.MENU_EVENT_CREATE: {
@@ -1233,7 +1250,6 @@
             if (duration < ViewConfiguration.getLongPressTimeout()) {
                 long millis = getSelectedTimeInMillis();
                 Utils.startActivity(getContext(), mDetailedView, millis);
-                mParentActivity.finish();
             } else {
                 mSelectionMode = SELECTION_LONGPRESS;
                 mRedrawScreen = true;
@@ -1274,7 +1290,6 @@
         case KeyEvent.KEYCODE_ENTER:
             long millis = getSelectedTimeInMillis();
             Utils.startActivity(getContext(), mDetailedView, millis);
-            mParentActivity.finish();
             return true;
         case KeyEvent.KEYCODE_DPAD_UP:
             if (mCursor.up()) {
@@ -1331,7 +1346,7 @@
 
         if (other != null) {
             other.normalize(true /* ignore DST */);
-            mNavigator.goTo(other);
+            mNavigator.goTo(other, true);
         } else if (redraw) {
             mRedrawScreen = true;
             invalidate();
diff --git a/src/com/android/calendar/Navigator.java b/src/com/android/calendar/Navigator.java
index e05a603..c8de34b 100644
--- a/src/com/android/calendar/Navigator.java
+++ b/src/com/android/calendar/Navigator.java
@@ -28,8 +28,9 @@
     /**
      * Changes the view to include the given time.
      * @param time the desired time to view.
+     * @animate enable animation
      */
-    void goTo(Time time);
+    void goTo(Time time, boolean animate);
     
     /**
      * Changes the view to include today's date.
diff --git a/src/com/android/calendar/SelectCalendarsActivity.java b/src/com/android/calendar/SelectCalendarsActivity.java
index 01037ab..429ec41 100644
--- a/src/com/android/calendar/SelectCalendarsActivity.java
+++ b/src/com/android/calendar/SelectCalendarsActivity.java
@@ -18,16 +18,18 @@
 
 import android.app.Activity;
 import android.app.AlertDialog;
-import android.content.AsyncQueryHandler;
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.database.Cursor;
+import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
 import android.provider.Calendar.Calendars;
+import android.provider.Calendar;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -45,8 +47,8 @@
     private static final String TAG = "Calendar";
     private View mView = null;
     private Cursor mCursor = null;
-    private QueryHandler mQueryHandler;
     private SelectCalendarsAdapter mAdapter;
+    private ContentResolver mContentResolver;
     private static final String[] PROJECTION = new String[] {
         Calendars._ID,
         Calendars.DISPLAY_NAME,
@@ -62,7 +64,6 @@
         setContentView(R.layout.calendars_activity);
         getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
                 Window.PROGRESS_INDETERMINATE_ON);
-        mQueryHandler = new QueryHandler(getContentResolver());
         mView = findViewById(R.id.calendars);
         ListView items = (ListView) mView.findViewById(R.id.items);
         Context context = mView.getContext();
@@ -70,18 +71,42 @@
                 Calendars.SYNC_EVENTS + "=1",
                 null /* selectionArgs */,
                 Calendars.DEFAULT_SORT_ORDER);
-                                     
+        mContentResolver = getContentResolver();
         mAdapter = new SelectCalendarsAdapter(context, mCursor);
         items.setAdapter(mAdapter);
         items.setOnItemClickListener(this);
         
         // Start a background sync to get the list of calendars from the server.
-        startCalendarSync();
+        startCalendarMetafeedSync();
     }
     
+    // Create an observer so that we can update the views whenever a
+    // Calendar changes.
+    private ContentObserver mObserver = new ContentObserver(new Handler())
+    {
+        @Override
+        public boolean deliverSelfNotifications() {
+            return true;
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            if (!isFinishing()) {
+                mCursor.requery();
+            }
+        }
+    };
+
     @Override
     public void onPause() {
         super.onPause();
+        mContentResolver.unregisterContentObserver(mObserver);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mContentResolver.registerContentObserver(Calendar.Events.CONTENT_URI, true, mObserver);
     }
     
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
@@ -115,13 +140,11 @@
         int mNumItems;
         long[] mCalendarIds;
         boolean[] mIsChecked;
-        ContentResolver mContentResolver;
         boolean mRemove;
         private int mCheckedCount;
         private Button mOkButtonInAddDeleteCalendar;
         
         public ChangeCalendarAction(boolean remove) {
-            mContentResolver = SelectCalendarsActivity.this.getContentResolver();
             mRemove = remove;
         }
 
@@ -169,14 +192,14 @@
                 values.put(Calendars.SYNC_EVENTS, selected);
                 mContentResolver.update(uri, values, null, null);
             }
-            
+
             // If there were any changes, then update the list of calendars
             // that are synced.
             if (changesFound) {
                 mCursor.requery();
             }
         }
-        
+
         public boolean onMenuItemClick(MenuItem item) {
             AlertDialog.Builder builder = new AlertDialog.Builder(SelectCalendarsActivity.this);
             String selection;
@@ -188,9 +211,7 @@
                 builder.setTitle(R.string.add_calendars);
                 selection = Calendars.SYNC_EVENTS + "=0";
             }
-            ContentResolver cr = getContentResolver();
-            // TODO this can cause ANRs http://b/1736511
-            Cursor cursor = cr.query(Calendars.CONTENT_URI, PROJECTION,
+            Cursor cursor = mContentResolver.query(Calendars.CONTENT_URI, PROJECTION,
                     selection, null /* selectionArgs */,
                     Calendars.DEFAULT_SORT_ORDER);
             if (cursor == null) {
@@ -226,69 +247,22 @@
         }
     }
     
-    private class QueryHandler extends AsyncQueryHandler {
-        public QueryHandler(ContentResolver cr) {
-            super(cr);
-        }
-
-        @Override
-        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
-            getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
-                    Window.PROGRESS_VISIBILITY_OFF);
-
-            // If the Activity is finishing, then close the cursor.
-            // Otherwise, use the new cursor in the adapter.
-            if (isFinishing()) {
-                stopManagingCursor(cursor);
-                cursor.close();
-            } else {
-                if (cursor.getCount() == 0) {
-                    // There are no calendars.  This might happen if we lost
-                    // the wireless connection (in airplane mode, for example).
-                    // Leave the current list of calendars alone and pop up
-                    // a dialog explaining that the connection is down.
-                    // But allow the user to add and remove calendars.
-                    return;
-                }
-                if (mCursor != null) {
-                    stopManagingCursor(mCursor);
-                }
-                mCursor = cursor;
-                startManagingCursor(cursor);
-                mAdapter.changeCursor(cursor);
-            }
-        }
-    }
-
-    // This class implements the menu option "Refresh list from server".
-    // (No longer used.)
-    public class RefreshAction implements Runnable {
-        public void run() {
-            startCalendarSync();
-        }
-    }
-    
-    // startCalendarSync() checks the server for an updated list of Calendars
-    // (in the background) using an AsyncQueryHandler.
+    // startCalendarMetafeedSync() checks the server for an updated list of
+    // Calendars (in the background).
     //
-    // Calendars are never removed from the phone due to a server sync.
-    // But if a Calendar is added on the web (and it is selected and not
+    // If a Calendar is added on the web (and it is selected and not
     // hidden) then it will be added to the list of calendars on the phone
-    // (when this asynchronous query finishes).  When a new calendar from the
+    // (when this finishes).  When a new calendar from the
     // web is added to the phone, then the events for that calendar are also
     // downloaded from the web.
     // 
     // This sync is done automatically in the background when the
     // SelectCalendars activity is started.
-    private void startCalendarSync() {
-        getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
-                Window.PROGRESS_VISIBILITY_ON);
-
-        // TODO: make sure the user has login info.
-        
-        Uri uri = Calendars.LIVE_CONTENT_URI;
-        mQueryHandler.startQuery(0, null, uri, PROJECTION,
-                Calendars.SYNC_EVENTS + "=1",
-                null, Calendars.DEFAULT_SORT_ORDER);
+    private void startCalendarMetafeedSync() {
+        Bundle extras = new Bundle();
+        extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+        extras.putBoolean("metafeedonly", true);
+        ContentResolver.requestSync(null /* all accounts */,
+                Calendars.CONTENT_URI.getAuthority(), extras);
     }
 }
diff --git a/src/com/android/calendar/Utils.java b/src/com/android/calendar/Utils.java
index 53c584c..c282798 100644
--- a/src/com/android/calendar/Utils.java
+++ b/src/com/android/calendar/Utils.java
@@ -17,9 +17,12 @@
 package com.android.calendar;
 
 import static android.provider.Calendar.EVENT_BEGIN_TIME;
+
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.content.res.Resources;
+import android.preference.PreferenceManager;
 import android.text.format.Time;
 import android.view.animation.AlphaAnimation;
 import android.widget.ViewFlipper;
@@ -30,10 +33,27 @@
 
         intent.setClassName(context, className);
         intent.putExtra(EVENT_BEGIN_TIME, time);
+        intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
 
         context.startActivity(intent);
     }
 
+    static void setDefaultView(Context context, int viewId) {
+        String activityString = CalendarApplication.ACTIVITY_NAMES[viewId];
+
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        SharedPreferences.Editor editor = prefs.edit();
+        if (viewId == CalendarApplication.AGENDA_VIEW_ID ||
+                viewId == CalendarApplication.DAY_VIEW_ID) {
+            // Record the (new) detail start view only for Agenda and Day
+            editor.putString(CalendarPreferenceActivity.KEY_DETAILED_VIEW, activityString);
+        }
+
+        // Record the (new) start view
+        editor.putString(CalendarPreferenceActivity.KEY_START_VIEW, activityString);
+        editor.commit();
+    }
+
     public static final Time timeFromIntent(Intent intent) {
         Time time = new Time();
         time.set(timeFromIntentInMillis(intent));
diff --git a/src/com/android/calendar/WeekActivity.java b/src/com/android/calendar/WeekActivity.java
index 0e06b51..43015f6 100644
--- a/src/com/android/calendar/WeekActivity.java
+++ b/src/com/android/calendar/WeekActivity.java
@@ -16,9 +16,11 @@
 
 package com.android.calendar;
 
+import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
+import android.text.format.Time;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
 import android.widget.ProgressBar;
@@ -55,6 +57,16 @@
     }
 
     @Override
+    protected void onNewIntent(Intent intent) {
+        long timeMillis = Utils.timeFromIntentInMillis(intent);
+        if (timeMillis > 0) {
+            Time time = new Time();
+            time.set(timeMillis);
+            goTo(time, false);
+        }
+    }
+
+    @Override
     protected void onResume() {
         super.onResume();
 
@@ -66,12 +78,6 @@
                 CalendarPreferenceActivity.DEFAULT_DETAILED_VIEW);
         view1.setDetailedView(str);
         view2.setDetailedView(str);
-
-        // Record Week View as the (new) start view
-        String activityString = CalendarApplication.ACTIVITY_NAMES[CalendarApplication.WEEK_VIEW_ID];
-        SharedPreferences.Editor editor = prefs.edit();
-        editor.putString(CalendarPreferenceActivity.KEY_START_VIEW, activityString);
-        editor.commit();
     }
 
     @Override
@@ -79,5 +85,8 @@
         super.onPause();
         CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
         mSelectedDay = view.getSelectedDay();
+
+        // Record Week View as the (new) start view
+        Utils.setDefaultView(this, CalendarApplication.WEEK_VIEW_ID);
     }
 }
diff --git a/src/com/android/calendar/WeekView.java b/src/com/android/calendar/WeekView.java
index b0b3244..ebff44c 100644
--- a/src/com/android/calendar/WeekView.java
+++ b/src/com/android/calendar/WeekView.java
@@ -26,7 +26,7 @@
     }
 
     private void init() {
-        mDrawTextInEventRect = false;
+        mDrawTextInEventRect = true;
         mNumDays = 7;
         mEventGeometry.setCellMargin(CELL_MARGIN);
     }
diff --git a/tests/src/com/android/calendar/FormatDateRangeTest.java b/tests/src/com/android/calendar/FormatDateRangeTest.java
index 6f0d775..548fc1c 100644
--- a/tests/src/com/android/calendar/FormatDateRangeTest.java
+++ b/tests/src/com/android/calendar/FormatDateRangeTest.java
@@ -30,7 +30,7 @@
  */
 public class FormatDateRangeTest extends AndroidTestCase {
 
-    private class DateTest {
+    static private class DateTest {
         public Time date1;
         public Time date2;
         public int flags;
diff --git a/tests/src/com/android/calendar/WeekNumberTest.java b/tests/src/com/android/calendar/WeekNumberTest.java
index 6b3774b..01f5746 100644
--- a/tests/src/com/android/calendar/WeekNumberTest.java
+++ b/tests/src/com/android/calendar/WeekNumberTest.java
@@ -29,7 +29,7 @@
  */
 public class WeekNumberTest extends AndroidTestCase {
 
-    private class DateAndWeekNumber {
+    static private class DateAndWeekNumber {
         public Time date;
         public Time allDayDate;
         public int expectedWeekNumber;