summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaman Tenneti <rtenneti@google.com>2018-11-01 12:05:17 -0700
committerandroid-build-merger <android-build-merger@google.com>2018-11-01 12:05:17 -0700
commitb6517440460d0e90352f2223f6e1c3ad76590071 (patch)
treedf65984f398a79bfec7fe9a3e6293ffe08e4d72b
parent7b051c6e9ef7922f08d9ebf664ac3087d5fa0552 (diff)
parent142020ee38cddceca76fc7c17712f1fed171d2e8 (diff)
downloadCalendar-b6517440460d0e90352f2223f6e1c3ad76590071.tar.gz
Merge "AOSP/Calendar - Minimal calendar app." am: a4438e61ac
am: 142020ee38 Change-Id: Ic21489e055a1ed8db1d71f0e4125e49799849272
-rw-r--r--AndroidManifest.xml31
-rw-r--r--proguard.flags13
-rw-r--r--res/layout-sw600dp/agenda_item.xml12
-rw-r--r--res/layout/agenda_item.xml12
-rw-r--r--res/layout/calendar_sync_item.xml11
-rw-r--r--res/layout/event_info.xml9
-rw-r--r--res/layout/event_info_dialog.xml10
-rw-r--r--res/layout/mini_calendar_item.xml11
-rw-r--r--res/layout/recurrencepicker.xml46
-rw-r--r--res/menu-land/all_in_one_title_bar.xml31
-rw-r--r--res/menu-sw600dp-land/all_in_one_title_bar.xml24
-rw-r--r--res/menu-sw600dp/all_in_one_title_bar.xml24
-rw-r--r--res/menu/all_in_one_title_bar.xml36
-rw-r--r--res/values-en-rGB/arrays.xml1
-rw-r--r--res/values/arrays.xml1
-rw-r--r--res/xml/calendar_settings_headers.xml3
-rw-r--r--res/xml/general_preferences.xml10
-rw-r--r--res/xml/searchable.xml4
-rw-r--r--src/com/android/calendar/AboutPreferences.java44
-rw-r--r--src/com/android/calendar/AbstractCalendarActivity.java30
-rw-r--r--src/com/android/calendar/AllInOneActivity.java261
-rw-r--r--src/com/android/calendar/AllInOneMenuExtensionsInterface.java36
-rw-r--r--src/com/android/calendar/AnalyticsLogger.java24
-rw-r--r--src/com/android/calendar/AsyncQueryService.java437
-rw-r--r--src/com/android/calendar/AsyncQueryServiceHelper.java308
-rw-r--r--src/com/android/calendar/CalendarApplication.java8
-rw-r--r--src/com/android/calendar/CalendarBackupAgent.java8
-rw-r--r--src/com/android/calendar/CalendarColorPickerDialog.java241
-rw-r--r--src/com/android/calendar/CalendarController.java173
-rw-r--r--src/com/android/calendar/CalendarEventModel.java944
-rw-r--r--src/com/android/calendar/CalendarRecentSuggestionsProvider.java33
-rw-r--r--src/com/android/calendar/CalendarSettingsActivity.java134
-rw-r--r--src/com/android/calendar/CalendarViewAdapter.java18
-rw-r--r--src/com/android/calendar/CloudNotificationBackplane.java30
-rw-r--r--src/com/android/calendar/ColorChipView.java138
-rw-r--r--src/com/android/calendar/ContactsAsyncHelper.java253
-rw-r--r--src/com/android/calendar/DayFragment.java5
-rw-r--r--src/com/android/calendar/DayOfMonthCursor.java189
-rw-r--r--src/com/android/calendar/DayView.java983
-rw-r--r--src/com/android/calendar/DeleteEventHelper.java466
-rw-r--r--src/com/android/calendar/EditResponseHelper.java153
-rw-r--r--src/com/android/calendar/EmailAddressAdapter.java69
-rw-r--r--src/com/android/calendar/EventInfoActivity.java11
-rw-r--r--src/com/android/calendar/EventInfoFragment.java1445
-rw-r--r--src/com/android/calendar/EventRecurrenceFormatter.java173
-rw-r--r--src/com/android/calendar/ExpandableTextView.java127
-rw-r--r--src/com/android/calendar/ExtensionsFactory.java169
-rw-r--r--src/com/android/calendar/GeneralPreferences.java34
-rw-r--r--src/com/android/calendar/GoogleCalendarUriIntentFilter.java252
-rw-r--r--src/com/android/calendar/OtherPreferences.java41
-rw-r--r--src/com/android/calendar/QuickResponseSettings.java100
-rw-r--r--src/com/android/calendar/RecipientAdapter.java40
-rw-r--r--src/com/android/calendar/SearchActivity.java388
-rw-r--r--src/com/android/calendar/Utils.java627
-rw-r--r--src/com/android/calendar/agenda/AgendaAdapter.java292
-rw-r--r--src/com/android/calendar/agenda/AgendaByDayAdapter.java684
-rw-r--r--src/com/android/calendar/agenda/AgendaFragment.java482
-rw-r--r--src/com/android/calendar/agenda/AgendaListView.java431
-rw-r--r--src/com/android/calendar/agenda/AgendaWindowAdapter.java1412
-rw-r--r--src/com/android/calendar/alerts/AlertActivity.java303
-rw-r--r--src/com/android/calendar/alerts/AlertAdapter.java156
-rw-r--r--src/com/android/calendar/alerts/AlertReceiver.java754
-rw-r--r--src/com/android/calendar/alerts/AlertService.java930
-rw-r--r--src/com/android/calendar/alerts/AlertUtils.java219
-rw-r--r--src/com/android/calendar/alerts/GlobalDismissManager.java463
-rw-r--r--src/com/android/calendar/alerts/QuickResponseActivity.java17
-rw-r--r--src/com/android/calendar/alerts/SnoozeAlarmsService.java89
-rw-r--r--src/com/android/calendar/event/AttendeesView.java486
-rw-r--r--src/com/android/calendar/event/CreateEventDialogFragment.java325
-rw-r--r--src/com/android/calendar/event/EditEventActivity.java174
-rw-r--r--src/com/android/calendar/event/EditEventFragment.java990
-rw-r--r--src/com/android/calendar/event/EditEventHelper.java1390
-rw-r--r--src/com/android/calendar/event/EditEventView.java1852
-rw-r--r--src/com/android/calendar/event/EventColorCache.java109
-rw-r--r--src/com/android/calendar/event/EventColorPickerDialog.java82
-rw-r--r--src/com/android/calendar/event/EventLocationAdapter.java472
-rw-r--r--src/com/android/calendar/event/EventViewUtils.java296
-rw-r--r--src/com/android/calendar/month/MonthByWeekAdapter.java27
-rw-r--r--src/com/android/calendar/month/MonthByWeekFragment.java22
-rw-r--r--src/com/android/calendar/month/MonthListView.java150
-rw-r--r--src/com/android/calendar/month/SimpleDayPickerFragment.java27
-rw-r--r--src/com/android/calendar/recurrencepicker/LinearLayoutWithMaxWidth.java43
-rw-r--r--src/com/android/calendar/recurrencepicker/RecurrencePickerDialog.java1322
-rw-r--r--src/com/android/calendar/recurrencepicker/WeekButton.java61
-rw-r--r--src/com/android/calendar/selectcalendars/CalendarColorCache.java109
-rw-r--r--src/com/android/calendar/selectcalendars/CalendarColorSquare.java47
-rw-r--r--src/com/android/calendar/selectcalendars/SelectCalendarsSimpleAdapter.java388
-rw-r--r--src/com/android/calendar/selectcalendars/SelectCalendarsSyncAdapter.java288
-rw-r--r--src/com/android/calendar/selectcalendars/SelectCalendarsSyncFragment.java217
-rw-r--r--src/com/android/calendar/selectcalendars/SelectSyncedCalendarsMultiAccountActivity.java174
-rw-r--r--src/com/android/calendar/selectcalendars/SelectSyncedCalendarsMultiAccountAdapter.java470
-rw-r--r--src/com/android/calendar/selectcalendars/SelectVisibleCalendarsActivity.java113
-rw-r--r--src/com/android/calendar/selectcalendars/SelectVisibleCalendarsFragment.java195
-rw-r--r--src/com/android/calendar/widget/CalendarAppWidgetProvider.java10
-rw-r--r--src/com/android/calendar/widget/CalendarAppWidgetService.java2
-rw-r--r--tests/src/com/android/calendar/AsyncQueryServiceTest.java661
-rw-r--r--tests/src/com/android/calendar/DbTestUtils.java4
-rw-r--r--tests/src/com/android/calendar/FormatDateRangeTest.java38
-rw-r--r--tests/src/com/android/calendar/UtilsTests.java298
-rw-r--r--tests/src/com/android/calendar/alerts/AlarmSchedulerTest.java319
-rw-r--r--tests/src/com/android/calendar/alerts/AlertServiceTest.java1033
-rw-r--r--tests/src/com/android/calendar/alerts/MockAlarmManager.java59
-rw-r--r--tests/src/com/android/calendar/alerts/Utils.java29
-rw-r--r--tests/src/com/android/calendar/event/EditEventHelperTest.java1645
-rw-r--r--tests/src/com/android/calendar/widget/CalendarAppWidgetServiceTest.java4
105 files changed, 84 insertions, 28760 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 5673a3b5..e4d81143 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -130,40 +130,9 @@
</intent-filter>
</activity>
- <activity android:name=".selectcalendars.SelectVisibleCalendarsActivity"
- android:label="@string/select_visible_calendars_title"
- android:theme="@android:style/Theme.Holo.Light"/>
-
- <activity android:name=".selectcalendars.SelectSyncedCalendarsMultiAccountActivity"
- android:label="@string/select_synced_calendars_title"
- android:theme="@android:style/Theme.Holo.Light"/>
-
- <activity android:name="CalendarSettingsActivity" android:label="@string/preferences_title"
- android:theme="@android:style/Theme.Holo.Light"/>
-
<!-- Declarations for search -->
<!-- Make all activities a searchable context -->
- <meta-data android:name="android.app.default_searchable"
- android:value="com.android.calendar.SearchActivity"/>
-
- <activity android:name="SearchActivity" android:label="@string/search_title"
- android:launchMode="singleTop" android:theme="@style/CalendarTheme.WithActionBar"
- android:windowSoftInputMode="stateAlwaysHidden"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.SEARCH"/>
- </intent-filter>
- <meta-data android:name="android.app.searchable" android:resource="@xml/searchable"/>
- </activity>
-
- <provider android:name=".CalendarRecentSuggestionsProvider"
- android:exported="false"
- android:authorities="com.android.calendar.CalendarRecentSuggestionsProvider" />
-
<!-- Declarations for alerts/reminders -->
- <activity android:name=".alerts.AlertActivity" android:launchMode="singleInstance"
- android:theme="@android:style/Theme.Holo.Dialog" android:excludeFromRecents="true" />
-
<activity android:name=".alerts.QuickResponseActivity" android:launchMode="singleInstance"
android:theme="@android:style/Theme.Holo.Dialog" android:excludeFromRecents="true"
android:label="@string/quick_response_dialog_title" />
diff --git a/proguard.flags b/proguard.flags
index bd7f0d54..923f6382 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -1,20 +1,11 @@
--keep class com.android.calendar.selectcalendars.SelectCalendarsSyncFragment
-keep class com.android.calendar.OtherPreferences
--keep class com.android.calendar.AboutPreferences
-keep class com.android.calendar.GeneralPreferences
-keepclassmembers class com.android.calendar.AllInOneActivity {
*** setControlsOffset(...);
}
--keepclassmembers class com.android.calendar.selectcalendars.SelectVisibleCalendarsActivity {
- *** handleSelectSyncedCalendarsClicked(...);
-}
-keepclassmembers class com.android.calendar.AllInOneActivity {
*** handleSelectSyncedCalendarsClicked(...);
}
--keepclassmembers class com.android.calendar.AsyncQueryService {
- *** setTestHandler(...);
- *** getLastCancelableOperation(...);
-}
-keepclassmembers class com.android.calendar.AsyncQueryServiceHelper$OperationInfo {
*** equivalent(...);
}
@@ -31,10 +22,6 @@
-keepclassmembers class com.android.calendar.month.MonthWeekEventsView {
*** setAnimateTodayAlpha(...);
}
--keepclassmembers class com.android.calendar.event.EditEventHelper {
- *** updateRecurrenceRule(...);
- *** extractDomain(...);
-}
-keepclassmembers class * implements android.content.SharedPreferences$Editor {
public *** apply();
diff --git a/res/layout-sw600dp/agenda_item.xml b/res/layout-sw600dp/agenda_item.xml
index f861f54c..b25fa154 100644
--- a/res/layout-sw600dp/agenda_item.xml
+++ b/res/layout-sw600dp/agenda_item.xml
@@ -30,18 +30,6 @@
android:layout_rowSpan="1"
android:layout_columnSpan="3"
android:layout_width="match_parent" />
- <com.android.calendar.ColorChipView
- android:id="@+id/agenda_item_color"
- android:layout_column="0"
- android:layout_row="1"
- android:layout_rowSpan="1"
- android:layout_width="32dip"
- android:layout_height="32dip"
- android:layout_gravity="top|left"
- android:layout_marginTop="12dip"
- android:layout_marginBottom="8dip"
- android:layout_marginLeft="16dip"
- android:layout_marginRight="8dip" />
<LinearLayout
android:id="@+id/agenda_item_text_container"
diff --git a/res/layout/agenda_item.xml b/res/layout/agenda_item.xml
index 16f81506..3180b816 100644
--- a/res/layout/agenda_item.xml
+++ b/res/layout/agenda_item.xml
@@ -30,18 +30,6 @@
android:layout_rowSpan="1"
android:layout_columnSpan="3"
android:layout_width="match_parent" />
- <com.android.calendar.ColorChipView
- android:id="@+id/agenda_item_color"
- android:layout_column="0"
- android:layout_row="1"
- android:layout_rowSpan="1"
- android:layout_width="24dip"
- android:layout_height="24dip"
- android:layout_gravity="top|left"
- android:layout_marginTop="8dip"
- android:layout_marginBottom="8dip"
- android:layout_marginLeft="16dip"
- android:layout_marginRight="8dip" />
<LinearLayout
android:id="@+id/agenda_item_text_container"
diff --git a/res/layout/calendar_sync_item.xml b/res/layout/calendar_sync_item.xml
index 02c2c5ce..ad8c8345 100644
--- a/res/layout/calendar_sync_item.xml
+++ b/res/layout/calendar_sync_item.xml
@@ -23,15 +23,6 @@
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip">
- <com.android.calendar.selectcalendars.CalendarColorSquare
- android:id="@+id/color"
- android:layout_height="32dip"
- android:layout_width="32dip"
- android:layout_marginLeft="13dip"
- android:layout_gravity="center_vertical"
- android:contentDescription="@string/calendar_square_color_picker_description"
- style="?android:attr/quickContactBadgeStyleWindowMedium" />
-
<LinearLayout
android:layout_width="0dip"
android:layout_height="wrap_content"
@@ -70,4 +61,4 @@
android:clickable="false"
android:longClickable="false"
android:focusable="false" />
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/res/layout/event_info.xml b/res/layout/event_info.xml
index 674fd1a0..07737abd 100644
--- a/res/layout/event_info.xml
+++ b/res/layout/event_info.xml
@@ -264,15 +264,6 @@
style="@style/TextAppearance.EditEvent_LabelSmall" />
</LinearLayout>
- <!-- GUEST LIST -->
- <com.android.calendar.event.AttendeesView
- android:id="@+id/long_attendee_list"
- android:textColor="@color/event_info_body_color"
- android:orientation="vertical"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:visibility="gone" />
-
<!-- REMINDERS -->
<TextView
android:layout_width="match_parent"
diff --git a/res/layout/event_info_dialog.xml b/res/layout/event_info_dialog.xml
index 2c51c77d..59e036a2 100644
--- a/res/layout/event_info_dialog.xml
+++ b/res/layout/event_info_dialog.xml
@@ -379,16 +379,6 @@
style="@style/TextAppearance.EditEvent_LabelSmall" />
</LinearLayout>
- <!-- GUEST LIST -->
- <com.android.calendar.event.AttendeesView
- android:id="@+id/long_attendee_list"
- android:textColor="@color/event_info_body_color"
- android:orientation="vertical"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:visibility="gone"
- android:layout_marginTop="5dip"/>
-
<!-- REMINDERS -->
<LinearLayout
android:id="@+id/reminders_row"
diff --git a/res/layout/mini_calendar_item.xml b/res/layout/mini_calendar_item.xml
index f4af9758..939bace2 100644
--- a/res/layout/mini_calendar_item.xml
+++ b/res/layout/mini_calendar_item.xml
@@ -25,17 +25,6 @@
android:layout_marginBottom="0dip"
android:layout_weight="1">
- <com.android.calendar.selectcalendars.CalendarColorSquare
- android:id="@+id/color"
- android:layout_height="20dip"
- android:layout_width="20dip"
- android:layout_marginLeft="16dip"
- android:layout_gravity="center_vertical"
- android:contentDescription="@string/calendar_square_color_picker_description"
- style="?android:attr/quickContactBadgeStyleWindowMedium"
- android:cropToPadding="true"
- />
-
<TextView android:id="@+id/calendar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/res/layout/recurrencepicker.xml b/res/layout/recurrencepicker.xml
index 49daabe4..d31cd980 100644
--- a/res/layout/recurrencepicker.xml
+++ b/res/layout/recurrencepicker.xml
@@ -116,52 +116,6 @@
android:layout_height="wrap_content" />
</LinearLayout>
- <com.android.calendar.recurrencepicker.LinearLayoutWithMaxWidth
- android:id="@+id/weekGroup"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="4dp"
- android:layout_marginRight="4dp"
- android:layout_marginTop="8dp"
- android:gravity="center_horizontal"
- android:orientation="horizontal" >
-
- <com.android.calendar.recurrencepicker.WeekButton style="@style/RecurrenceDayOfWeekStyle" />
-
- <com.android.calendar.recurrencepicker.WeekButton style="@style/RecurrenceDayOfWeekStyle" />
-
- <com.android.calendar.recurrencepicker.WeekButton style="@style/RecurrenceDayOfWeekStyle" />
-
- <com.android.calendar.recurrencepicker.WeekButton style="@style/RecurrenceDayOfWeekStyle" />
-
- <com.android.calendar.recurrencepicker.WeekButton style="@style/RecurrenceDayOfWeekStyle" />
-
- <com.android.calendar.recurrencepicker.WeekButton style="@style/RecurrenceDayOfWeekStyle" />
-
- <com.android.calendar.recurrencepicker.WeekButton style="@style/RecurrenceDayOfWeekStyle" />
- </com.android.calendar.recurrencepicker.LinearLayoutWithMaxWidth>
-
- <com.android.calendar.recurrencepicker.LinearLayoutWithMaxWidth
- android:id="@+id/weekGroup2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="4dp"
- android:layout_marginRight="4dp"
- android:gravity="center_horizontal"
- android:orientation="horizontal"
- android:visibility="gone" >
-
- <com.android.calendar.recurrencepicker.WeekButton style="@style/RecurrenceDayOfWeekStyle" />
-
- <com.android.calendar.recurrencepicker.WeekButton style="@style/RecurrenceDayOfWeekStyle" />
-
- <com.android.calendar.recurrencepicker.WeekButton style="@style/RecurrenceDayOfWeekStyle" />
-
- <com.android.calendar.recurrencepicker.WeekButton
- style="@style/RecurrenceDayOfWeekStyle"
- android:visibility="invisible" />
- </com.android.calendar.recurrencepicker.LinearLayoutWithMaxWidth>
-
<RadioGroup
android:id="@+id/monthGroup"
android:layout_width="match_parent"
diff --git a/res/menu-land/all_in_one_title_bar.xml b/res/menu-land/all_in_one_title_bar.xml
index 9f20fa41..062b777c 100644
--- a/res/menu-land/all_in_one_title_bar.xml
+++ b/res/menu-land/all_in_one_title_bar.xml
@@ -23,37 +23,6 @@
android:icon="@drawable/today_icon"
android:showAsAction="withText|ifRoom" />
<item
- android:id="@+id/action_create_event"
- android:alphabeticShortcut="n"
- android:title="@string/event_create"
- android:icon="@drawable/ic_menu_add_event_holo_light"
- android:showAsAction="ifRoom" />
- <item
- android:id="@+id/action_refresh"
- android:alphabeticShortcut="r"
- android:showAsAction="never"
- android:title="@string/calendar_refresh"
- android:icon="@drawable/ic_menu_refresh_holo_light" />
- <item
- android:id="@+id/action_search"
- android:alphabeticShortcut="f"
- android:title="@string/search"
- android:icon="@drawable/ic_menu_search_holo_light"
- android:showAsAction="never|collapseActionView"
- android:actionViewClass="android.widget.SearchView"
- android:imeOptions="actionSearch" />
- <item
- android:id="@+id/action_select_visible_calendars"
- android:title="@string/menu_select_visible_calendars"
- android:icon="@drawable/ic_menu_select_visible_calendars_holo_light"
- android:showAsAction="never" />
- <item
- android:id="@+id/action_settings"
- android:alphabeticShortcut="s"
- android:showAsAction="never"
- android:title="@string/menu_preferences"
- android:icon="@drawable/ic_menu_settings_holo_light" />
- <item
android:id="@+id/action_hide_controls"
android:alphabeticShortcut="h"
android:showAsAction="never"
diff --git a/res/menu-sw600dp-land/all_in_one_title_bar.xml b/res/menu-sw600dp-land/all_in_one_title_bar.xml
index 8e877e56..5b285fd8 100644
--- a/res/menu-sw600dp-land/all_in_one_title_bar.xml
+++ b/res/menu-sw600dp-land/all_in_one_title_bar.xml
@@ -23,31 +23,7 @@
android:icon="@drawable/today_icon"
android:showAsAction="always|withText" />
<item
- android:id="@+id/action_create_event"
- android:alphabeticShortcut="n"
- android:title="@string/event_create"
- android:showAsAction="ifRoom"
- android:icon="@drawable/ic_menu_add_event_holo_light" />
- <item
- android:id="@+id/action_refresh"
- android:alphabeticShortcut="r"
- android:title="@string/calendar_refresh"
- android:icon="@drawable/ic_menu_refresh_holo_light" />
- <item
- android:id="@+id/action_search"
- android:alphabeticShortcut="f"
- android:title="@string/search"
- android:icon="@drawable/ic_menu_search_holo_light"
- android:showAsAction="collapseActionView"
- android:actionViewClass="android.widget.SearchView"
- android:imeOptions="actionSearch" />
- <item
android:id="@+id/action_hide_controls"
android:alphabeticShortcut="h"
android:title="@string/hide_controls" />
- <item
- android:id="@+id/action_settings"
- android:alphabeticShortcut="s"
- android:title="@string/menu_preferences"
- android:icon="@drawable/ic_menu_settings_holo_light" />
</menu>
diff --git a/res/menu-sw600dp/all_in_one_title_bar.xml b/res/menu-sw600dp/all_in_one_title_bar.xml
index 6d88e7ae..5b285fd8 100644
--- a/res/menu-sw600dp/all_in_one_title_bar.xml
+++ b/res/menu-sw600dp/all_in_one_title_bar.xml
@@ -23,31 +23,7 @@
android:icon="@drawable/today_icon"
android:showAsAction="always|withText" />
<item
- android:id="@+id/action_create_event"
- android:alphabeticShortcut="n"
- android:showAsAction="ifRoom"
- android:title="@string/event_create"
- android:icon="@drawable/ic_menu_add_event_holo_light" />
- <item
- android:id="@+id/action_refresh"
- android:alphabeticShortcut="r"
- android:title="@string/calendar_refresh"
- android:icon="@drawable/ic_menu_refresh_holo_light" />
- <item
- android:id="@+id/action_search"
- android:alphabeticShortcut="f"
- android:title="@string/search"
- android:icon="@drawable/ic_menu_search_holo_light"
- android:showAsAction="collapseActionView"
- android:actionViewClass="android.widget.SearchView"
- android:imeOptions="actionSearch" />
- <item
android:id="@+id/action_hide_controls"
android:alphabeticShortcut="h"
android:title="@string/hide_controls" />
- <item
- android:id="@+id/action_settings"
- android:alphabeticShortcut="s"
- android:title="@string/menu_preferences"
- android:icon="@drawable/ic_menu_settings_holo_light" />
</menu>
diff --git a/res/menu/all_in_one_title_bar.xml b/res/menu/all_in_one_title_bar.xml
index ad3598b2..64dc84a5 100644
--- a/res/menu/all_in_one_title_bar.xml
+++ b/res/menu/all_in_one_title_bar.xml
@@ -23,40 +23,4 @@
android:icon="@drawable/today_icon"
android:showAsAction="ifRoom"
android:orderInCategory="1" />
- <item
- android:id="@+id/action_create_event"
- android:alphabeticShortcut="n"
- android:title="@string/event_create"
- android:icon="@drawable/ic_menu_add_event_holo_light"
- android:showAsAction="never"
- android:orderInCategory="2" />
- <item
- android:id="@+id/action_refresh"
- android:alphabeticShortcut="r"
- android:title="@string/calendar_refresh"
- android:icon="@drawable/ic_menu_refresh_holo_light"
- android:showAsAction="never"
- android:orderInCategory="3" />
- <item
- android:id="@+id/action_search"
- android:alphabeticShortcut="f"
- android:title="@string/search"
- android:icon="@drawable/ic_menu_search_holo_light"
- android:showAsAction="never|collapseActionView"
- android:actionViewClass="android.widget.SearchView"
- android:imeOptions="actionSearch"
- android:orderInCategory="4" />
- <item
- android:id="@+id/action_select_visible_calendars"
- android:title="@string/menu_select_visible_calendars"
- android:icon="@drawable/ic_menu_select_visible_calendars_holo_light"
- android:showAsAction="never"
- android:orderInCategory="5" />
- <item
- android:id="@+id/action_settings"
- android:alphabeticShortcut="s"
- android:title="@string/menu_preferences"
- android:icon="@drawable/ic_menu_settings_holo_light"
- android:showAsAction="never"
- android:orderInCategory="10" />
</menu>
diff --git a/res/values-en-rGB/arrays.xml b/res/values-en-rGB/arrays.xml
index 943b2cb2..fb3842ac 100644
--- a/res/values-en-rGB/arrays.xml
+++ b/res/values-en-rGB/arrays.xml
@@ -105,7 +105,6 @@
<item msgid="5917946202321434335">"Day"</item>
<item msgid="6248480754959562740">"Week"</item>
<item msgid="4298472806133153766">"Month"</item>
- <item msgid="5033084974413793845">"Agenda"</item>
</string-array>
<string-array name="preferences_skip_reminders_labels">
<item msgid="2285927842308686988">"Only if declined"</item>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index b14854a3..d14abe43 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -221,7 +221,6 @@
<item>Day</item>
<item>Week</item>
<item>Month</item>
- <item>Agenda</item>
</string-array>
<!-- Experimental options for skipping reminders. [CHAR LIMIT = 37] -->
diff --git a/res/xml/calendar_settings_headers.xml b/res/xml/calendar_settings_headers.xml
index a5a5ae72..d497d2d0 100644
--- a/res/xml/calendar_settings_headers.xml
+++ b/res/xml/calendar_settings_headers.xml
@@ -18,7 +18,4 @@
xmlns:android="http://schemas.android.com/apk/res/android">
<header android:fragment="com.android.calendar.GeneralPreferences"
android:title="@string/menu_general_preferences" />
-
- <header android:fragment="com.android.calendar.AboutPreferences"
- android:title="@string/menu_about_preferences" />
</preference-headers>
diff --git a/res/xml/general_preferences.xml b/res/xml/general_preferences.xml
index 5f64b362..c8b5ab7d 100644
--- a/res/xml/general_preferences.xml
+++ b/res/xml/general_preferences.xml
@@ -41,10 +41,6 @@
android:dependency="preferences_home_tz_enabled"
android:defaultValue="@string/preferences_home_tz_default"
android:title="@string/preferences_home_tz_title" />
- <PreferenceScreen
- android:key="preferences_clear_search_history"
- android:title="@string/preferences_clear_search_history_title"
- android:summary="@string/preferences_clear_search_history_summary" />
</PreferenceCategory>
<PreferenceCategory
android:key="preferences_alerts_category"
@@ -80,12 +76,6 @@
android:entries="@array/preferences_default_reminder_labels"
android:entryValues="@array/preferences_default_reminder_values"
android:dialogTitle="@string/preferences_default_reminder_dialog" />
-
- <PreferenceScreen
- android:key="preferences_quick_responses"
- android:fragment="com.android.calendar.QuickResponseSettings"
- android:title="@string/quick_response_settings"
- android:summary="@string/quick_response_settings_summary" />
</PreferenceCategory>
</PreferenceScreen>
diff --git a/res/xml/searchable.xml b/res/xml/searchable.xml
index ad01b7e1..52a3442d 100644
--- a/res/xml/searchable.xml
+++ b/res/xml/searchable.xml
@@ -15,14 +15,10 @@
-->
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
- android:value="com.android.calendar.SearchActivity"
android:label="@string/app_label"
android:searchMode="showSearchLabelAsBadge"
android:voiceSearchMode="showVoiceSearchButton|launchRecognizer"
android:voiceLanguageModel="free_form"
-
- android:searchSuggestAuthority="com.android.calendar.CalendarRecentSuggestionsProvider"
- android:searchSuggestSelection=" ? "
android:imeOptions="actionSearch" >
</searchable>
diff --git a/src/com/android/calendar/AboutPreferences.java b/src/com/android/calendar/AboutPreferences.java
deleted file mode 100644
index ab682f3f..00000000
--- a/src/com/android/calendar/AboutPreferences.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.calendar;
-
-import android.app.Activity;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Bundle;
-import android.preference.PreferenceFragment;
-
-import com.android.calendar.R;
-
-public class AboutPreferences extends PreferenceFragment {
- private static final String BUILD_VERSION = "build_version";
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- addPreferencesFromResource(R.xml.about_preferences);
-
- final Activity activity = getActivity();
- try {
- final PackageInfo packageInfo =
- activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0);
- findPreference(BUILD_VERSION).setSummary(packageInfo.versionName);
- } catch (NameNotFoundException e) {
- findPreference(BUILD_VERSION).setSummary("?");
- }
- }
-} \ No newline at end of file
diff --git a/src/com/android/calendar/AbstractCalendarActivity.java b/src/com/android/calendar/AbstractCalendarActivity.java
deleted file mode 100644
index a80787dc..00000000
--- a/src/com/android/calendar/AbstractCalendarActivity.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.calendar;
-
-import android.app.Activity;
-
-public abstract class AbstractCalendarActivity extends Activity {
- protected AsyncQueryService mService;
-
- public synchronized AsyncQueryService getAsyncQueryService() {
- if (mService == null) {
- mService = new AsyncQueryService(this);
- }
- return mService;
- }
-}
diff --git a/src/com/android/calendar/AllInOneActivity.java b/src/com/android/calendar/AllInOneActivity.java
index 0e1feb49..d7780379 100644
--- a/src/com/android/calendar/AllInOneActivity.java
+++ b/src/com/android/calendar/AllInOneActivity.java
@@ -26,6 +26,7 @@ import android.animation.Animator.AnimatorListener;
import android.animation.ObjectAnimator;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
+import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
@@ -60,17 +61,13 @@ import android.view.accessibility.AccessibilityEvent;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
-import android.widget.SearchView;
-import android.widget.SearchView.OnSuggestionListener;
import android.widget.TextView;
import com.android.calendar.CalendarController.EventHandler;
import com.android.calendar.CalendarController.EventInfo;
import com.android.calendar.CalendarController.EventType;
import com.android.calendar.CalendarController.ViewType;
-import com.android.calendar.agenda.AgendaFragment;
import com.android.calendar.month.MonthByWeekFragment;
-import com.android.calendar.selectcalendars.SelectVisibleCalendarsFragment;
import java.io.IOException;
import java.util.List;
@@ -82,9 +79,9 @@ import static android.provider.CalendarContract.EXTRA_EVENT_ALL_DAY;
import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
-public class AllInOneActivity extends AbstractCalendarActivity implements EventHandler,
- OnSharedPreferenceChangeListener, SearchView.OnQueryTextListener, ActionBar.TabListener,
- ActionBar.OnNavigationListener, OnSuggestionListener {
+public class AllInOneActivity extends Activity implements EventHandler,
+ OnSharedPreferenceChangeListener, ActionBar.TabListener,
+ ActionBar.OnNavigationListener {
private static final String TAG = "AllInOneActivity";
private static final boolean DEBUG = false;
private static final String EVENT_INFO_FRAGMENT_TAG = "EventInfoFragment";
@@ -105,8 +102,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
private CalendarController mController;
private static boolean mIsMultipane;
private static boolean mIsTabletConfig;
- private static boolean mShowAgendaWithMonth;
- private static boolean mShowEventDetailsWithAgenda;
private boolean mOnSaveInstanceStateCalled = false;
private boolean mBackToPreviousView = false;
private ContentResolver mContentResolver;
@@ -126,7 +121,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
private View mSecondaryPane;
private String mTimeZone;
private boolean mShowCalendarControls;
- private boolean mShowEventInfoFullScreenAgenda;
private boolean mShowEventInfoFullScreen;
private int mWeekNum;
private int mCalendarControlsAnimationTime;
@@ -144,9 +138,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
private ActionBar.Tab mDayTab;
private ActionBar.Tab mWeekTab;
private ActionBar.Tab mMonthTab;
- private ActionBar.Tab mAgendaTab;
- private SearchView mSearchView;
- private MenuItem mSearchMenu;
private MenuItem mControlsMenu;
private Menu mOptionsMenu;
private CalendarViewAdapter mActionBarMenuSpinnerAdapter;
@@ -164,9 +155,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
private LayoutParams mControlsParams;
private LinearLayout.LayoutParams mVerticalControlsParams;
- private AllInOneMenuExtensionsInterface mExtensions = ExtensionsFactory
- .getAllInOneMenuExtensions();
-
private final AnimatorListener mSlideAnimationDoneListener = new AnimatorListener() {
@Override
@@ -220,23 +208,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
new AccountManagerCallback<Bundle>() {
@Override
public void run(AccountManagerFuture<Bundle> future) {
- if (future.isCancelled()) {
- return;
- }
- try {
- Bundle result = future.getResult();
- boolean setupSkipped = result.getBoolean("setupSkipped");
-
- if (setupSkipped) {
- Utils.setSharedPreference(AllInOneActivity.this,
- GeneralPreferences.KEY_SKIP_SETUP, true);
- }
-
- } catch (OperationCanceledException ignore) {
- // The account creation process was canceled
- } catch (IOException ignore) {
- } catch (AuthenticatorException ignore) {
- }
}
}, null);
}
@@ -277,8 +248,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
}
};
- BroadcastReceiver mCalIntentReceiver;
-
@Override
protected void onNewIntent(Intent intent) {
String action = intent.getAction();
@@ -302,9 +271,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
@Override
protected void onCreate(Bundle icicle) {
- if (Utils.getSharedPreference(this, OtherPreferences.KEY_OTHER_1, false)) {
- setTheme(R.style.CalendarTheme_WithActionBarWallpaper);
- }
super.onCreate(icicle);
if (icicle != null && icicle.containsKey(BUNDLE_KEY_CHECK_ACCOUNTS)) {
@@ -312,8 +278,7 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
}
// Launch add google account if this is first time and there are no
// accounts yet
- if (mCheckForAccounts
- && !Utils.getSharedPreference(this, GeneralPreferences.KEY_SKIP_SETUP, false)) {
+ if (mCheckForAccounts) {
mHandler = new QueryHandler(this.getContentResolver());
mHandler.startQuery(0, null, Calendars.CONTENT_URI, new String[] {
@@ -379,17 +344,11 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
mControlsAnimateHeight = (int)res.getDimension(R.dimen.calendar_controls_height);
- mHideControls = !Utils.getSharedPreference(
- this, GeneralPreferences.KEY_SHOW_CONTROLS, true);
+ mHideControls = true;
mIsMultipane = Utils.getConfigBool(this, R.bool.multiple_pane_config);
mIsTabletConfig = Utils.getConfigBool(this, R.bool.tablet_config);
- mShowAgendaWithMonth = Utils.getConfigBool(this, R.bool.show_agenda_with_month);
mShowCalendarControls =
Utils.getConfigBool(this, R.bool.show_calendar_controls);
- mShowEventDetailsWithAgenda =
- Utils.getConfigBool(this, R.bool.show_event_details_with_agenda);
- mShowEventInfoFullScreenAgenda =
- Utils.getConfigBool(this, R.bool.agenda_show_event_info_full_screen);
mShowEventInfoFullScreen =
Utils.getConfigBool(this, R.bool.show_event_info_full_screen);
mCalendarControlsAnimationTime = res.getInteger(R.integer.calendar_controls_animation_time);
@@ -476,7 +435,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
mActionBar.setListNavigationCallbacks(mActionBarMenuSpinnerAdapter, this);
switch (viewType) {
case ViewType.AGENDA:
- mActionBar.setSelectedNavigationItem(BUTTON_AGENDA_INDEX);
break;
case ViewType.DAY:
mActionBar.setSelectedNavigationItem(BUTTON_DAY_INDEX);
@@ -554,8 +512,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
Utils.setMidnightUpdater(mHandler, mTimeChangesUpdater, mTimeZone);
// Make sure the today icon is up to date
invalidateOptionsMenu();
-
- mCalIntentReceiver = Utils.setTimeChangesReceiver(this, mTimeChangesUpdater);
}
@Override
@@ -579,7 +535,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
Utils.setDefaultView(this, mController.getViewType());
}
Utils.resetMidnightUpdater(mHandler, mTimeChangesUpdater);
- Utils.clearTimeChangesReceiver(this, mCalIntentReceiver);
}
@Override
@@ -592,18 +547,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
public void onSaveInstanceState(Bundle outState) {
mOnSaveInstanceStateCalled = true;
super.onSaveInstanceState(outState);
- outState.putLong(BUNDLE_KEY_RESTORE_TIME, mController.getTime());
- outState.putInt(BUNDLE_KEY_RESTORE_VIEW, mCurrentView);
- if (mCurrentView == ViewType.EDIT) {
- outState.putLong(BUNDLE_KEY_EVENT_ID, mController.getEventId());
- } else if (mCurrentView == ViewType.AGENDA) {
- FragmentManager fm = getFragmentManager();
- Fragment f = fm.findFragmentById(R.id.main_pane);
- if (f instanceof AgendaFragment) {
- outState.putLong(BUNDLE_KEY_EVENT_ID, ((AgendaFragment)f).getLastShowEventId());
- }
- }
- outState.putBoolean(BUNDLE_KEY_CHECK_ACCOUNTS, mCheckForAccounts);
}
@Override
@@ -628,11 +571,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
Fragment miniMonthFrag = new MonthByWeekFragment(timeMillis, true);
ft.replace(R.id.mini_month, miniMonthFrag);
mController.registerEventHandler(R.id.mini_month, (EventHandler) miniMonthFrag);
-
- Fragment selectCalendarsFrag = new SelectVisibleCalendarsFragment();
- ft.replace(R.id.calendar_list, selectCalendarsFrag);
- mController.registerEventHandler(
- R.id.calendar_list, (EventHandler) selectCalendarsFrag);
}
if (!mShowCalendarControls || viewType == ViewType.EDIT) {
mMiniMonth.setVisibility(View.GONE);
@@ -685,10 +623,7 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
Time t = new Time(mTimeZone);
t.set(timeMillis);
- if (viewType == ViewType.AGENDA && icicle != null) {
- mController.sendEvent(this, EventType.GO_TO, t, null,
- icicle.getLong(BUNDLE_KEY_EVENT_ID, -1), viewType);
- } else if (viewType != ViewType.EDIT) {
+ if (viewType != ViewType.EDIT) {
mController.sendEvent(this, EventType.GO_TO, t, null, -1, viewType);
}
}
@@ -708,22 +643,8 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
mOptionsMenu = menu;
getMenuInflater().inflate(R.menu.all_in_one_title_bar, menu);
- // Add additional options (if any).
- Integer extensionMenuRes = mExtensions.getExtensionMenuResource(menu);
- if (extensionMenuRes != null) {
- getMenuInflater().inflate(extensionMenuRes, menu);
- }
-
- mSearchMenu = menu.findItem(R.id.action_search);
- mSearchView = (SearchView) mSearchMenu.getActionView();
- if (mSearchView != null) {
- Utils.setUpSearchView(mSearchView, this);
- mSearchView.setOnQueryTextListener(this);
- mSearchView.setOnSuggestionListener(this);
- }
-
// Hide the "show/hide controls" button if this is a phone
- // or the view type is "Month" or "Agenda".
+ // or the view type is "Month".
mControlsMenu = menu.findItem(R.id.action_hide_controls);
if (!mShowCalendarControls) {
@@ -732,8 +653,7 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
mControlsMenu.setEnabled(false);
}
} else if (mControlsMenu != null && mController != null
- && (mController.getViewType() == ViewType.MONTH ||
- mController.getViewType() == ViewType.AGENDA)) {
+ && (mController.getViewType() == ViewType.MONTH)) {
mControlsMenu.setVisible(false);
mControlsMenu.setEnabled(false);
} else if (mControlsMenu != null){
@@ -758,37 +678,13 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
int viewType = ViewType.CURRENT;
long extras = CalendarController.EXTRA_GOTO_TIME;
final int itemId = item.getItemId();
- if (itemId == R.id.action_refresh) {
- mController.refreshCalendars();
- return true;
- } else if (itemId == R.id.action_today) {
+ if (itemId == R.id.action_today) {
viewType = ViewType.CURRENT;
t = new Time(mTimeZone);
t.setToNow();
extras |= CalendarController.EXTRA_GOTO_TODAY;
- } else if (itemId == R.id.action_create_event) {
- t = new Time();
- t.set(mController.getTime());
- if (t.minute > 30) {
- t.hour++;
- t.minute = 0;
- } else if (t.minute > 0 && t.minute < 30) {
- t.minute = 30;
- }
- mController.sendEventRelatedEvent(
- this, EventType.CREATE_EVENT, -1, t.toMillis(true), 0, 0, 0, -1);
- return true;
- } else if (itemId == R.id.action_select_visible_calendars) {
- mController.sendEvent(this, EventType.LAUNCH_SELECT_VISIBLE_CALENDARS, null, null,
- 0, 0);
- return true;
- } else if (itemId == R.id.action_settings) {
- mController.sendEvent(this, EventType.LAUNCH_SETTINGS, null, null, 0, 0);
- return true;
} else if (itemId == R.id.action_hide_controls) {
mHideControls = !mHideControls;
- Utils.setSharedPreference(
- this, GeneralPreferences.KEY_SHOW_CONTROLS, !mHideControls);
item.setTitle(mHideControls ? mShowString : mHideString);
if (!mHideControls) {
mMiniMonth.setVisibility(View.VISIBLE);
@@ -802,10 +698,9 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
ObjectAnimator.setFrameDelay(0);
slideAnimation.start();
return true;
- } else if (itemId == R.id.action_search) {
- return false;
} else {
- return mExtensions.handleItemSelected(item, this);
+ Log.d(TAG, "Unsupported itemId: " + itemId);
+ return true;
}
mController.sendEvent(this, EventType.GO_TO, t, null, t, -1, viewType, extras, null, null);
return true;
@@ -858,16 +753,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
// Remove this when transition to and from month view looks fine.
boolean doTransition = viewType != ViewType.MONTH && mCurrentView != ViewType.MONTH;
FragmentManager fragmentManager = getFragmentManager();
- // Check if our previous view was an Agenda view
- // TODO remove this if framework ever supports nested fragments
- if (mCurrentView == ViewType.AGENDA) {
- // If it was, we need to do some cleanup on it to prevent the
- // edit/delete buttons from coming back on a rotation.
- Fragment oldFrag = fragmentManager.findFragmentById(viewId);
- if (oldFrag instanceof AgendaFragment) {
- ((AgendaFragment) oldFrag).removeFragments(fragmentManager);
- }
- }
if (viewType != mCurrentView) {
// The rules for this previous view are different than the
@@ -882,14 +767,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
Fragment secFrag = null;
switch (viewType) {
case ViewType.AGENDA:
- if (mActionBar != null && (mActionBar.getSelectedTab() != mAgendaTab)) {
- mActionBar.selectTab(mAgendaTab);
- }
- if (mActionBarMenuSpinnerAdapter != null) {
- mActionBar.setSelectedNavigationItem(CalendarViewAdapter.AGENDA_BUTTON_INDEX);
- }
- frag = new AgendaFragment(timeMillis, false);
- ExtensionsFactory.getAnalyticsLogger(getBaseContext()).trackView("agenda");
break;
case ViewType.DAY:
if (mActionBar != null && (mActionBar.getSelectedTab() != mDayTab)) {
@@ -899,7 +776,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
mActionBar.setSelectedNavigationItem(CalendarViewAdapter.DAY_BUTTON_INDEX);
}
frag = new DayFragment(timeMillis, 1);
- ExtensionsFactory.getAnalyticsLogger(getBaseContext()).trackView("day");
break;
case ViewType.MONTH:
if (mActionBar != null && (mActionBar.getSelectedTab() != mMonthTab)) {
@@ -909,10 +785,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
mActionBar.setSelectedNavigationItem(CalendarViewAdapter.MONTH_BUTTON_INDEX);
}
frag = new MonthByWeekFragment(timeMillis, false);
- if (mShowAgendaWithMonth) {
- secFrag = new AgendaFragment(timeMillis, false);
- }
- ExtensionsFactory.getAnalyticsLogger(getBaseContext()).trackView("month");
break;
case ViewType.WEEK:
default:
@@ -923,7 +795,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
mActionBar.setSelectedNavigationItem(CalendarViewAdapter.WEEK_BUTTON_INDEX);
}
frag = new DayFragment(timeMillis, 7);
- ExtensionsFactory.getAnalyticsLogger(getBaseContext()).trackView("week");
break;
}
@@ -940,8 +811,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
// Show date only on tablet configurations in views different than Agenda
if (!mIsTabletConfig) {
mDateRange.setVisibility(View.GONE);
- } else if (viewType != ViewType.AGENDA) {
- mDateRange.setVisibility(View.VISIBLE);
} else {
mDateRange.setVisibility(View.GONE);
}
@@ -962,30 +831,11 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
}
ft.replace(viewId, frag);
- if (mShowAgendaWithMonth) {
-
- // Show/hide secondary fragment
-
- if (secFrag != null) {
- ft.replace(R.id.secondary_pane, secFrag);
- mSecondaryPane.setVisibility(View.VISIBLE);
- } else {
- mSecondaryPane.setVisibility(View.GONE);
- Fragment f = fragmentManager.findFragmentById(R.id.secondary_pane);
- if (f != null) {
- ft.remove(f);
- }
- mController.deregisterEventHandler(R.id.secondary_pane);
- }
- }
if (DEBUG) {
Log.d(TAG, "Adding handler with viewId " + viewId + " and type " + viewType);
}
// If the key is already registered this will replace it
mController.registerEventHandler(viewId, (EventHandler) frag);
- if (secFrag != null) {
- mController.registerEventHandler(viewId, (EventHandler) secFrag);
- }
if (doCommit) {
if (DEBUG) {
@@ -1051,8 +901,7 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
}
if (mHomeTime != null
- && (mCurrentView == ViewType.DAY || mCurrentView == ViewType.WEEK
- || mCurrentView == ViewType.AGENDA)
+ && (mCurrentView == ViewType.DAY || mCurrentView == ViewType.WEEK)
&& !TextUtils.equals(mTimeZone, Time.getCurrentTimezone())) {
Time time = new Time(mTimeZone);
time.setToNow();
@@ -1098,13 +947,10 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
setMainPane(
null, R.id.main_pane, event.viewType, event.startTime.toMillis(false), false);
- if (mSearchView != null) {
- mSearchView.clearFocus();
- }
if (mShowCalendarControls) {
int animationSize = (mOrientation == Configuration.ORIENTATION_LANDSCAPE) ?
mControlsAnimateWidth : mControlsAnimateHeight;
- boolean noControlsView = event.viewType == ViewType.MONTH || event.viewType == ViewType.AGENDA;
+ boolean noControlsView = event.viewType == ViewType.MONTH;
if (mControlsMenu != null) {
mControlsMenu.setVisible(!noControlsView);
mControlsMenu.setEnabled(!noControlsView);
@@ -1131,8 +977,7 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
mCalendarsList.setVisibility(View.VISIBLE);
mMiniMonthContainer.setVisibility(View.VISIBLE);
if (!mHideControls &&
- (mController.getPreviousViewType() == ViewType.MONTH ||
- mController.getPreviousViewType() == ViewType.AGENDA)) {
+ (mController.getPreviousViewType() == ViewType.MONTH)) {
final ObjectAnimator slideAnimation = ObjectAnimator.ofInt(this,
"controlsOffset", animationSize, 0);
slideAnimation.setDuration(mCalendarControlsAnimationTime);
@@ -1152,32 +997,15 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
// do not create the event info fragment here, it will be created by the Agenda
// fragment
- if (mCurrentView == ViewType.AGENDA && mShowEventDetailsWithAgenda) {
- if (event.startTime != null && event.endTime != null) {
- // Event is all day , adjust the goto time to local time
- if (event.isAllDay()) {
- Utils.convertAlldayUtcToLocal(
- event.startTime, event.startTime.toMillis(false), mTimeZone);
- Utils.convertAlldayUtcToLocal(
- event.endTime, event.endTime.toMillis(false), mTimeZone);
- }
- mController.sendEvent(this, EventType.GO_TO, event.startTime, event.endTime,
- event.selectedTime, event.id, ViewType.AGENDA,
- CalendarController.EXTRA_GOTO_TIME, null, null);
- } else if (event.selectedTime != null) {
- mController.sendEvent(this, EventType.GO_TO, event.selectedTime,
- event.selectedTime, event.id, ViewType.AGENDA);
- }
- } else {
+ if (mCurrentView != ViewType.AGENDA) {
// TODO Fix the temp hack below: && mCurrentView !=
// ViewType.AGENDA
- if (event.selectedTime != null && mCurrentView != ViewType.AGENDA) {
+ if (event.selectedTime != null) {
mController.sendEvent(this, EventType.GO_TO, event.selectedTime,
event.selectedTime, -1, ViewType.CURRENT);
}
int response = event.getResponse();
- if ((mCurrentView == ViewType.AGENDA && mShowEventInfoFullScreenAgenda) ||
- ((mCurrentView == ViewType.DAY || (mCurrentView == ViewType.WEEK) ||
+ if (((mCurrentView == ViewType.DAY || (mCurrentView == ViewType.WEEK) ||
mCurrentView == ViewType.MONTH) && mShowEventInfoFullScreen)){
// start event info as activity
Intent intent = new Intent(Intent.ACTION_VIEW);
@@ -1195,8 +1023,7 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
EventInfoFragment fragment = new EventInfoFragment(this,
event.id, event.startTime.toMillis(false),
event.endTime.toMillis(false), response, true,
- EventInfoFragment.DIALOG_WINDOW_STYLE,
- null /* No reminders to explicitly pass in. */);
+ EventInfoFragment.DIALOG_WINDOW_STYLE);
fragment.setDialogParams(event.x, event.y, mActionBar.getHeight());
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
@@ -1219,33 +1046,12 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
updateSecondaryTitleFields(displayTime);
}
- // Needs to be in proguard whitelist
- // Specified as listener via android:onClick in a layout xml
- public void handleSelectSyncedCalendarsClicked(View v) {
- mController.sendEvent(this, EventType.LAUNCH_SETTINGS, null, null, null, 0, 0,
- CalendarController.EXTRA_GOTO_TIME, null,
- null);
- }
-
@Override
public void eventsChanged() {
mController.sendEvent(this, EventType.EVENTS_CHANGED, null, null, -1, ViewType.CURRENT);
}
@Override
- public boolean onQueryTextChange(String newText) {
- return false;
- }
-
- @Override
- public boolean onQueryTextSubmit(String query) {
- mSearchMenu.collapseActionView();
- mController.sendEvent(this, EventType.SEARCH, null, null, -1, ViewType.CURRENT, 0, query,
- getComponentName());
- return true;
- }
-
- @Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Log.w(TAG, "TabSelected AllInOne=" + this + " finishing:" + this.isFinishing());
if (tab == mDayTab && mCurrentView != ViewType.DAY) {
@@ -1254,13 +1060,11 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.WEEK);
} else if (tab == mMonthTab && mCurrentView != ViewType.MONTH) {
mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.MONTH);
- } else if (tab == mAgendaTab && mCurrentView != ViewType.AGENDA) {
- mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.AGENDA);
} else {
Log.w(TAG, "TabSelected event from unknown tab: "
+ (tab == null ? "null" : tab.getText()));
Log.w(TAG, "CurrentView:" + mCurrentView + " Tab:" + tab.toString() + " Day:" + mDayTab
- + " Week:" + mWeekTab + " Month:" + mMonthTab + " Agenda:" + mAgendaTab);
+ + " Week:" + mWeekTab + " Month:" + mMonthTab);
}
}
@@ -1292,36 +1096,13 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
}
break;
case CalendarViewAdapter.AGENDA_BUTTON_INDEX:
- if (mCurrentView != ViewType.AGENDA) {
- mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.AGENDA);
- }
break;
default:
Log.w(TAG, "ItemSelected event from unknown button: " + itemPosition);
Log.w(TAG, "CurrentView:" + mCurrentView + " Button:" + itemPosition +
- " Day:" + mDayTab + " Week:" + mWeekTab + " Month:" + mMonthTab +
- " Agenda:" + mAgendaTab);
+ " Day:" + mDayTab + " Week:" + mWeekTab + " Month:" + mMonthTab);
break;
}
return false;
}
-
- @Override
- public boolean onSuggestionSelect(int position) {
- return false;
- }
-
- @Override
- public boolean onSuggestionClick(int position) {
- mSearchMenu.collapseActionView();
- return false;
- }
-
- @Override
- public boolean onSearchRequested() {
- if (mSearchMenu != null) {
- mSearchMenu.expandActionView();
- }
- return false;
- }
}
diff --git a/src/com/android/calendar/AllInOneMenuExtensionsInterface.java b/src/com/android/calendar/AllInOneMenuExtensionsInterface.java
deleted file mode 100644
index 877db548..00000000
--- a/src/com/android/calendar/AllInOneMenuExtensionsInterface.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2012 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.Context;
-import android.view.Menu;
-import android.view.MenuItem;
-
-/*
- * Interface for additional options in the AllInOne menu.
- */
-public interface AllInOneMenuExtensionsInterface {
- /**
- * Returns additional options.
- */
- Integer getExtensionMenuResource(Menu menu);
-
- /**
- * Handle selection of the additional options.
- */
- boolean handleItemSelected(MenuItem item, Context context);
-}
diff --git a/src/com/android/calendar/AnalyticsLogger.java b/src/com/android/calendar/AnalyticsLogger.java
deleted file mode 100644
index c98984f2..00000000
--- a/src/com/android/calendar/AnalyticsLogger.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.android.calendar;
-
-import android.content.Context;
-
-/**
- * Interface for analytics logging.
- */
-public interface AnalyticsLogger {
-
- /**
- * Open backend of logger.
- *
- * @param context need to open backend of logger.
- * @return true, if analytics logging is ready to be use.
- */
- public boolean initialize(Context context);
-
- /**
- * Track what view people are using.
- *
- * @param name of the view.
- */
- public void trackView(String name);
-}
diff --git a/src/com/android/calendar/AsyncQueryService.java b/src/com/android/calendar/AsyncQueryService.java
deleted file mode 100644
index 1f022db9..00000000
--- a/src/com/android/calendar/AsyncQueryService.java
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.calendar;
-
-import com.android.calendar.AsyncQueryServiceHelper.OperationInfo;
-
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * A helper class that executes {@link ContentResolver} calls in a background
- * {@link android.app.Service}. This minimizes the chance of the call getting
- * lost because the caller ({@link android.app.Activity}) is killed. It is
- * designed for easy migration from {@link android.content.AsyncQueryHandler}
- * which calls the {@link ContentResolver} in a background thread. This supports
- * query/insert/update/delete and also batch mode i.e.
- * {@link ContentProviderOperation}. It also supports delay execution and cancel
- * which allows for time-limited undo. Note that there's one queue per
- * application which serializes all the calls.
- */
-public class AsyncQueryService extends Handler {
- private static final String TAG = "AsyncQuery";
- static final boolean localLOGV = false;
-
- // Used for generating unique tokens for calls to this service
- private static AtomicInteger mUniqueToken = new AtomicInteger(0);
-
- private Context mContext;
- private Handler mHandler = this; // can be overridden for testing
-
- /**
- * Data class which holds into info of the queued operation
- */
- public static class Operation {
- static final int EVENT_ARG_QUERY = 1;
- static final int EVENT_ARG_INSERT = 2;
- static final int EVENT_ARG_UPDATE = 3;
- static final int EVENT_ARG_DELETE = 4;
- static final int EVENT_ARG_BATCH = 5;
-
- /**
- * unique identify for cancellation purpose
- */
- public int token;
-
- /**
- * One of the EVENT_ARG_ constants in the class describing the operation
- */
- public int op;
-
- /**
- * {@link SystemClock.elapsedRealtime()} based
- */
- public long scheduledExecutionTime;
-
- protected static char opToChar(int op) {
- switch (op) {
- case Operation.EVENT_ARG_QUERY:
- return 'Q';
- case Operation.EVENT_ARG_INSERT:
- return 'I';
- case Operation.EVENT_ARG_UPDATE:
- return 'U';
- case Operation.EVENT_ARG_DELETE:
- return 'D';
- case Operation.EVENT_ARG_BATCH:
- return 'B';
- default:
- return '?';
- }
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("Operation [op=");
- builder.append(op);
- builder.append(", token=");
- builder.append(token);
- builder.append(", scheduledExecutionTime=");
- builder.append(scheduledExecutionTime);
- builder.append("]");
- return builder.toString();
- }
- }
-
- public AsyncQueryService(Context context) {
- mContext = context;
- }
-
- /**
- * returns a practically unique token for db operations
- */
- public final int getNextToken() {
- return mUniqueToken.getAndIncrement();
- }
-
- /**
- * Gets the last delayed operation. It is typically used for canceling.
- *
- * @return Operation object which contains of the last cancelable operation
- */
- public final Operation getLastCancelableOperation() {
- return AsyncQueryServiceHelper.getLastCancelableOperation();
- }
-
- /**
- * Attempts to cancel operation that has not already started. Note that
- * there is no guarantee that the operation will be canceled. They still may
- * result in a call to on[Query/Insert/Update/Delete/Batch]Complete after
- * this call has completed.
- *
- * @param token The token representing the operation to be canceled. If
- * multiple operations have the same token they will all be
- * canceled.
- */
- public final int cancelOperation(int token) {
- return AsyncQueryServiceHelper.cancelOperation(token);
- }
-
- /**
- * This method begins an asynchronous query. When the query is done
- * {@link #onQueryComplete} is called.
- *
- * @param token A token passed into {@link #onQueryComplete} to identify the
- * query.
- * @param cookie An object that gets passed into {@link #onQueryComplete}
- * @param uri The URI, using the content:// scheme, for the content to
- * retrieve.
- * @param projection A list of which columns to return. Passing null will
- * return all columns, which is discouraged to prevent reading
- * data from storage that isn't going to be used.
- * @param selection A filter declaring which rows to return, formatted as an
- * SQL WHERE clause (excluding the WHERE itself). Passing null
- * will return all rows for the given URI.
- * @param selectionArgs You may include ?s in selection, which will be
- * replaced by the values from selectionArgs, in the order that
- * they appear in the selection. The values will be bound as
- * Strings.
- * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
- * (excluding the ORDER BY itself). Passing null will use the
- * default sort order, which may be unordered.
- */
- public void startQuery(int token, Object cookie, Uri uri, String[] projection,
- String selection, String[] selectionArgs, String orderBy) {
- OperationInfo info = new OperationInfo();
- info.op = Operation.EVENT_ARG_QUERY;
- info.resolver = mContext.getContentResolver();
-
- info.handler = mHandler;
- info.token = token;
- info.cookie = cookie;
- info.uri = uri;
- info.projection = projection;
- info.selection = selection;
- info.selectionArgs = selectionArgs;
- info.orderBy = orderBy;
-
- AsyncQueryServiceHelper.queueOperation(mContext, info);
- }
-
- /**
- * This method begins an asynchronous insert. When the insert operation is
- * done {@link #onInsertComplete} is called.
- *
- * @param token A token passed into {@link #onInsertComplete} to identify
- * the insert operation.
- * @param cookie An object that gets passed into {@link #onInsertComplete}
- * @param uri the Uri passed to the insert operation.
- * @param initialValues the ContentValues parameter passed to the insert
- * operation.
- * @param delayMillis delay in executing the operation. This operation will
- * execute before the delayed time when another operation is
- * added. Useful for implementing single level undo.
- */
- public void startInsert(int token, Object cookie, Uri uri, ContentValues initialValues,
- long delayMillis) {
- OperationInfo info = new OperationInfo();
- info.op = Operation.EVENT_ARG_INSERT;
- info.resolver = mContext.getContentResolver();
- info.handler = mHandler;
-
- info.token = token;
- info.cookie = cookie;
- info.uri = uri;
- info.values = initialValues;
- info.delayMillis = delayMillis;
-
- AsyncQueryServiceHelper.queueOperation(mContext, info);
- }
-
- /**
- * This method begins an asynchronous update. When the update operation is
- * done {@link #onUpdateComplete} is called.
- *
- * @param token A token passed into {@link #onUpdateComplete} to identify
- * the update operation.
- * @param cookie An object that gets passed into {@link #onUpdateComplete}
- * @param uri the Uri passed to the update operation.
- * @param values the ContentValues parameter passed to the update operation.
- * @param selection A filter declaring which rows to update, formatted as an
- * SQL WHERE clause (excluding the WHERE itself). Passing null
- * will update all rows for the given URI.
- * @param selectionArgs You may include ?s in selection, which will be
- * replaced by the values from selectionArgs, in the order that
- * they appear in the selection. The values will be bound as
- * Strings.
- * @param delayMillis delay in executing the operation. This operation will
- * execute before the delayed time when another operation is
- * added. Useful for implementing single level undo.
- */
- public void startUpdate(int token, Object cookie, Uri uri, ContentValues values,
- String selection, String[] selectionArgs, long delayMillis) {
- OperationInfo info = new OperationInfo();
- info.op = Operation.EVENT_ARG_UPDATE;
- info.resolver = mContext.getContentResolver();
- info.handler = mHandler;
-
- info.token = token;
- info.cookie = cookie;
- info.uri = uri;
- info.values = values;
- info.selection = selection;
- info.selectionArgs = selectionArgs;
- info.delayMillis = delayMillis;
-
- AsyncQueryServiceHelper.queueOperation(mContext, info);
- }
-
- /**
- * This method begins an asynchronous delete. When the delete operation is
- * done {@link #onDeleteComplete} is called.
- *
- * @param token A token passed into {@link #onDeleteComplete} to identify
- * the delete operation.
- * @param cookie An object that gets passed into {@link #onDeleteComplete}
- * @param uri the Uri passed to the delete operation.
- * @param selection A filter declaring which rows to delete, formatted as an
- * SQL WHERE clause (excluding the WHERE itself). Passing null
- * will delete all rows for the given URI.
- * @param selectionArgs You may include ?s in selection, which will be
- * replaced by the values from selectionArgs, in the order that
- * they appear in the selection. The values will be bound as
- * Strings.
- * @param delayMillis delay in executing the operation. This operation will
- * execute before the delayed time when another operation is
- * added. Useful for implementing single level undo.
- */
- public void startDelete(int token, Object cookie, Uri uri, String selection,
- String[] selectionArgs, long delayMillis) {
- OperationInfo info = new OperationInfo();
- info.op = Operation.EVENT_ARG_DELETE;
- info.resolver = mContext.getContentResolver();
- info.handler = mHandler;
-
- info.token = token;
- info.cookie = cookie;
- info.uri = uri;
- info.selection = selection;
- info.selectionArgs = selectionArgs;
- info.delayMillis = delayMillis;
-
- AsyncQueryServiceHelper.queueOperation(mContext, info);
- }
-
- /**
- * This method begins an asynchronous {@link ContentProviderOperation}. When
- * the operation is done {@link #onBatchComplete} is called.
- *
- * @param token A token passed into {@link #onDeleteComplete} to identify
- * the delete operation.
- * @param cookie An object that gets passed into {@link #onDeleteComplete}
- * @param authority the authority used for the
- * {@link ContentProviderOperation}.
- * @param cpo the {@link ContentProviderOperation} to be executed.
- * @param delayMillis delay in executing the operation. This operation will
- * execute before the delayed time when another operation is
- * added. Useful for implementing single level undo.
- */
- public void startBatch(int token, Object cookie, String authority,
- ArrayList<ContentProviderOperation> cpo, long delayMillis) {
- OperationInfo info = new OperationInfo();
- info.op = Operation.EVENT_ARG_BATCH;
- info.resolver = mContext.getContentResolver();
- info.handler = mHandler;
-
- info.token = token;
- info.cookie = cookie;
- info.authority = authority;
- info.cpo = cpo;
- info.delayMillis = delayMillis;
-
- AsyncQueryServiceHelper.queueOperation(mContext, info);
- }
-
- /**
- * Called when an asynchronous query is completed.
- *
- * @param token the token to identify the query, passed in from
- * {@link #startQuery}.
- * @param cookie the cookie object passed in from {@link #startQuery}.
- * @param cursor The cursor holding the results from the query.
- */
- protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- if (localLOGV) {
- Log.d(TAG, "########## default onQueryComplete");
- }
- }
-
- /**
- * Called when an asynchronous insert is completed.
- *
- * @param token the token to identify the query, passed in from
- * {@link #startInsert}.
- * @param cookie the cookie object that's passed in from
- * {@link #startInsert}.
- * @param uri the uri returned from the insert operation.
- */
- protected void onInsertComplete(int token, Object cookie, Uri uri) {
- if (localLOGV) {
- Log.d(TAG, "########## default onInsertComplete");
- }
- }
-
- /**
- * Called when an asynchronous update is completed.
- *
- * @param token the token to identify the query, passed in from
- * {@link #startUpdate}.
- * @param cookie the cookie object that's passed in from
- * {@link #startUpdate}.
- * @param result the result returned from the update operation
- */
- protected void onUpdateComplete(int token, Object cookie, int result) {
- if (localLOGV) {
- Log.d(TAG, "########## default onUpdateComplete");
- }
- }
-
- /**
- * Called when an asynchronous delete is completed.
- *
- * @param token the token to identify the query, passed in from
- * {@link #startDelete}.
- * @param cookie the cookie object that's passed in from
- * {@link #startDelete}.
- * @param result the result returned from the delete operation
- */
- protected void onDeleteComplete(int token, Object cookie, int result) {
- if (localLOGV) {
- Log.d(TAG, "########## default onDeleteComplete");
- }
- }
-
- /**
- * Called when an asynchronous {@link ContentProviderOperation} is
- * completed.
- *
- * @param token the token to identify the query, passed in from
- * {@link #startDelete}.
- * @param cookie the cookie object that's passed in from
- * {@link #startDelete}.
- * @param results the result returned from executing the
- * {@link ContentProviderOperation}
- */
- protected void onBatchComplete(int token, Object cookie, ContentProviderResult[] results) {
- if (localLOGV) {
- Log.d(TAG, "########## default onBatchComplete");
- }
- }
-
- @Override
- public void handleMessage(Message msg) {
- OperationInfo info = (OperationInfo) msg.obj;
-
- int token = msg.what;
- int op = msg.arg1;
-
- if (localLOGV) {
- Log.d(TAG, "AsyncQueryService.handleMessage: token=" + token + ", op=" + op
- + ", result=" + info.result);
- }
-
- // pass token back to caller on each callback.
- switch (op) {
- case Operation.EVENT_ARG_QUERY:
- onQueryComplete(token, info.cookie, (Cursor) info.result);
- break;
-
- case Operation.EVENT_ARG_INSERT:
- onInsertComplete(token, info.cookie, (Uri) info.result);
- break;
-
- case Operation.EVENT_ARG_UPDATE:
- onUpdateComplete(token, info.cookie, (Integer) info.result);
- break;
-
- case Operation.EVENT_ARG_DELETE:
- onDeleteComplete(token, info.cookie, (Integer) info.result);
- break;
-
- case Operation.EVENT_ARG_BATCH:
- onBatchComplete(token, info.cookie, (ContentProviderResult[]) info.result);
- break;
- }
- }
-
-// @VisibleForTesting
- protected void setTestHandler(Handler handler) {
- mHandler = handler;
- }
-}
diff --git a/src/com/android/calendar/AsyncQueryServiceHelper.java b/src/com/android/calendar/AsyncQueryServiceHelper.java
index 615a779f..c6e0a2bc 100644
--- a/src/com/android/calendar/AsyncQueryServiceHelper.java
+++ b/src/com/android/calendar/AsyncQueryServiceHelper.java
@@ -16,8 +16,6 @@
package com.android.calendar;
-import com.android.calendar.AsyncQueryService.Operation;
-
import android.app.IntentService;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
@@ -43,194 +41,6 @@ import java.util.concurrent.TimeUnit;
public class AsyncQueryServiceHelper extends IntentService {
private static final String TAG = "AsyncQuery";
- private static final PriorityQueue<OperationInfo> sWorkQueue =
- new PriorityQueue<OperationInfo>();
-
- protected Class<AsyncQueryService> mService = AsyncQueryService.class;
-
- protected static class OperationInfo implements Delayed{
- public int token; // Used for cancel
- public int op;
- public ContentResolver resolver;
- public Uri uri;
- public String authority;
- public Handler handler;
- public String[] projection;
- public String selection;
- public String[] selectionArgs;
- public String orderBy;
- public Object result;
- public Object cookie;
- public ContentValues values;
- public ArrayList<ContentProviderOperation> cpo;
-
- /**
- * delayMillis is relative time e.g. 10,000 milliseconds
- */
- public long delayMillis;
-
- /**
- * scheduleTimeMillis is the time scheduled for this to be processed.
- * e.g. SystemClock.elapsedRealtime() + 10,000 milliseconds Based on
- * {@link android.os.SystemClock#elapsedRealtime }
- */
- private long mScheduledTimeMillis = 0;
-
- // @VisibleForTesting
- void calculateScheduledTime() {
- mScheduledTimeMillis = SystemClock.elapsedRealtime() + delayMillis;
- }
-
- // @Override // Uncomment with Java6
- public long getDelay(TimeUnit unit) {
- return unit.convert(mScheduledTimeMillis - SystemClock.elapsedRealtime(),
- TimeUnit.MILLISECONDS);
- }
-
- // @Override // Uncomment with Java6
- public int compareTo(Delayed another) {
- OperationInfo anotherArgs = (OperationInfo) another;
- if (this.mScheduledTimeMillis == anotherArgs.mScheduledTimeMillis) {
- return 0;
- } else if (this.mScheduledTimeMillis < anotherArgs.mScheduledTimeMillis) {
- return -1;
- } else {
- return 1;
- }
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("OperationInfo [\n\t token= ");
- builder.append(token);
- builder.append(",\n\t op= ");
- builder.append(Operation.opToChar(op));
- builder.append(",\n\t uri= ");
- builder.append(uri);
- builder.append(",\n\t authority= ");
- builder.append(authority);
- builder.append(",\n\t delayMillis= ");
- builder.append(delayMillis);
- builder.append(",\n\t mScheduledTimeMillis= ");
- builder.append(mScheduledTimeMillis);
- builder.append(",\n\t resolver= ");
- builder.append(resolver);
- builder.append(",\n\t handler= ");
- builder.append(handler);
- builder.append(",\n\t projection= ");
- builder.append(Arrays.toString(projection));
- builder.append(",\n\t selection= ");
- builder.append(selection);
- builder.append(",\n\t selectionArgs= ");
- builder.append(Arrays.toString(selectionArgs));
- builder.append(",\n\t orderBy= ");
- builder.append(orderBy);
- builder.append(",\n\t result= ");
- builder.append(result);
- builder.append(",\n\t cookie= ");
- builder.append(cookie);
- builder.append(",\n\t values= ");
- builder.append(values);
- builder.append(",\n\t cpo= ");
- builder.append(cpo);
- builder.append("\n]");
- return builder.toString();
- }
-
- /**
- * Compares an user-visible operation to this private OperationInfo
- * object
- *
- * @param o operation to be compared
- * @return true if logically equivalent
- */
- public boolean equivalent(Operation o) {
- return o.token == this.token && o.op == this.op;
- }
- }
-
- /**
- * Queues the operation for execution
- *
- * @param context
- * @param args OperationInfo object describing the operation
- */
- static public void queueOperation(Context context, OperationInfo args) {
- // Set the schedule time for execution based on the desired delay.
- args.calculateScheduledTime();
-
- synchronized (sWorkQueue) {
- sWorkQueue.add(args);
- sWorkQueue.notify();
- }
-
- context.startService(new Intent(context, AsyncQueryServiceHelper.class));
- }
-
- /**
- * Gets the last delayed operation. It is typically used for canceling.
- *
- * @return Operation object which contains of the last cancelable operation
- */
- static public Operation getLastCancelableOperation() {
- long lastScheduleTime = Long.MIN_VALUE;
- Operation op = null;
-
- synchronized (sWorkQueue) {
- // Unknown order even for a PriorityQueue
- Iterator<OperationInfo> it = sWorkQueue.iterator();
- while (it.hasNext()) {
- OperationInfo info = it.next();
- if (info.delayMillis > 0 && lastScheduleTime < info.mScheduledTimeMillis) {
- if (op == null) {
- op = new Operation();
- }
-
- op.token = info.token;
- op.op = info.op;
- op.scheduledExecutionTime = info.mScheduledTimeMillis;
-
- lastScheduleTime = info.mScheduledTimeMillis;
- }
- }
- }
-
- if (AsyncQueryService.localLOGV) {
- Log.d(TAG, "getLastCancelableOperation -> Operation:" + Operation.opToChar(op.op)
- + " token:" + op.token);
- }
- return op;
- }
-
- /**
- * Attempts to cancel operation that has not already started. Note that
- * there is no guarantee that the operation will be canceled. They still may
- * result in a call to on[Query/Insert/Update/Delete/Batch]Complete after
- * this call has completed.
- *
- * @param token The token representing the operation to be canceled. If
- * multiple operations have the same token they will all be
- * canceled.
- */
- static public int cancelOperation(int token) {
- int canceled = 0;
- synchronized (sWorkQueue) {
- Iterator<OperationInfo> it = sWorkQueue.iterator();
- while (it.hasNext()) {
- if (it.next().token == token) {
- it.remove();
- ++canceled;
- }
- }
- }
-
- if (AsyncQueryService.localLOGV) {
- Log.d(TAG, "cancelOperation(" + token + ") -> " + canceled);
- }
- return canceled;
- }
-
public AsyncQueryServiceHelper(String name) {
super(name);
}
@@ -241,138 +51,20 @@ public class AsyncQueryServiceHelper extends IntentService {
@Override
protected void onHandleIntent(Intent intent) {
- OperationInfo args;
-
- if (AsyncQueryService.localLOGV) {
- Log.d(TAG, "onHandleIntent: queue size=" + sWorkQueue.size());
- }
- synchronized (sWorkQueue) {
- while (true) {
- /*
- * This method can be called with no work because of
- * cancellations
- */
- if (sWorkQueue.size() == 0) {
- return;
- } else if (sWorkQueue.size() == 1) {
- OperationInfo first = sWorkQueue.peek();
- long waitTime = first.mScheduledTimeMillis - SystemClock.elapsedRealtime();
- if (waitTime > 0) {
- try {
- sWorkQueue.wait(waitTime);
- } catch (InterruptedException e) {
- }
- }
- }
-
- args = sWorkQueue.poll();
- if (args != null) {
- // Got work to do. Break out of waiting loop
- break;
- }
- }
- }
-
- if (AsyncQueryService.localLOGV) {
- Log.d(TAG, "onHandleIntent: " + args);
- }
-
- ContentResolver resolver = args.resolver;
- if (resolver != null) {
-
- switch (args.op) {
- case Operation.EVENT_ARG_QUERY:
- Cursor cursor;
- try {
- cursor = resolver.query(args.uri, args.projection, args.selection,
- args.selectionArgs, args.orderBy);
- /*
- * Calling getCount() causes the cursor window to be
- * filled, which will make the first access on the main
- * thread a lot faster
- */
- if (cursor != null) {
- cursor.getCount();
- }
- } catch (Exception e) {
- Log.w(TAG, e.toString());
- cursor = null;
- }
-
- args.result = cursor;
- break;
-
- case Operation.EVENT_ARG_INSERT:
- args.result = resolver.insert(args.uri, args.values);
- break;
-
- case Operation.EVENT_ARG_UPDATE:
- args.result = resolver.update(args.uri, args.values, args.selection,
- args.selectionArgs);
- break;
-
- case Operation.EVENT_ARG_DELETE:
- try {
- args.result = resolver.delete(args.uri, args.selection, args.selectionArgs);
- } catch (IllegalArgumentException e) {
- Log.w(TAG, "Delete failed.");
- Log.w(TAG, e.toString());
- args.result = 0;
- }
-
- break;
-
- case Operation.EVENT_ARG_BATCH:
- try {
- args.result = resolver.applyBatch(args.authority, args.cpo);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- args.result = null;
- } catch (OperationApplicationException e) {
- Log.e(TAG, e.toString());
- args.result = null;
- }
- break;
- }
-
- /*
- * passing the original token value back to the caller on top of the
- * event values in arg1.
- */
- Message reply = args.handler.obtainMessage(args.token);
- reply.obj = args;
- reply.arg1 = args.op;
-
- if (AsyncQueryService.localLOGV) {
- Log.d(TAG, "onHandleIntent: op=" + Operation.opToChar(args.op) + ", token="
- + reply.what);
- }
-
- reply.sendToTarget();
- }
}
@Override
public void onStart(Intent intent, int startId) {
- if (AsyncQueryService.localLOGV) {
- Log.d(TAG, "onStart startId=" + startId);
- }
super.onStart(intent, startId);
}
@Override
public void onCreate() {
- if (AsyncQueryService.localLOGV) {
- Log.d(TAG, "onCreate");
- }
super.onCreate();
}
@Override
public void onDestroy() {
- if (AsyncQueryService.localLOGV) {
- Log.d(TAG, "onDestroy");
- }
super.onDestroy();
}
}
diff --git a/src/com/android/calendar/CalendarApplication.java b/src/com/android/calendar/CalendarApplication.java
index 7f1854d0..d0ca4698 100644
--- a/src/com/android/calendar/CalendarApplication.java
+++ b/src/com/android/calendar/CalendarApplication.java
@@ -28,13 +28,5 @@ public class CalendarApplication extends Application {
* service, etc. of Calendar
*/
GeneralPreferences.setDefaultValues(this);
-
- // Save the version number, for upcoming 'What's new' screen. This will be later be
- // moved to that implementation.
- Utils.setSharedPreference(this, GeneralPreferences.KEY_VERSION,
- Utils.getVersionCode(this));
-
- // Initialize the registry mapping some custom behavior.
- ExtensionsFactory.init(getAssets());
}
}
diff --git a/src/com/android/calendar/CalendarBackupAgent.java b/src/com/android/calendar/CalendarBackupAgent.java
index 0e9f9d72..02456fdc 100644
--- a/src/com/android/calendar/CalendarBackupAgent.java
+++ b/src/com/android/calendar/CalendarBackupAgent.java
@@ -31,19 +31,11 @@ public class CalendarBackupAgent extends BackupAgentHelper
@Override
public void onCreate() {
- addHelper(SHARED_KEY, new SharedPreferencesBackupHelper(this,
- GeneralPreferences.SHARED_PREFS_NAME));
}
@Override
public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
throws IOException {
- // See Utils.getRingTonePreference for more info
- final Editor editor = getSharedPreferences(
- GeneralPreferences.SHARED_PREFS_NAME_NO_BACKUP, Context.MODE_PRIVATE).edit();
- editor.putString(GeneralPreferences.KEY_ALERTS_RINGTONE,
- GeneralPreferences.DEFAULT_RINGTONE).commit();
-
super.onRestore(data, appVersionCode, newState);
}
}
diff --git a/src/com/android/calendar/CalendarColorPickerDialog.java b/src/com/android/calendar/CalendarColorPickerDialog.java
deleted file mode 100644
index e72d1962..00000000
--- a/src/com/android/calendar/CalendarColorPickerDialog.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 2013 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.app.Activity;
-import android.app.Dialog;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.CalendarContract.Calendars;
-import android.provider.CalendarContract.Colors;
-import android.util.SparseIntArray;
-
-import com.android.colorpicker.ColorPickerDialog;
-import com.android.colorpicker.ColorPickerSwatch.OnColorSelectedListener;
-import com.android.colorpicker.HsvColorComparator;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-public class CalendarColorPickerDialog extends ColorPickerDialog {
-
- private static final int NUM_COLUMNS = 4;
-
- private static final String KEY_CALENDAR_ID = "calendar_id";
- private static final String KEY_COLOR_KEYS = "color_keys";
-
- private static final int TOKEN_QUERY_CALENDARS = 1 << 1;
- private static final int TOKEN_QUERY_COLORS = 1 << 2;
-
- static final String[] CALENDARS_PROJECTION = new String[] {
- Calendars.ACCOUNT_NAME,
- Calendars.ACCOUNT_TYPE,
- Calendars.CALENDAR_COLOR
- };
-
- static final int CALENDARS_INDEX_ACCOUNT_NAME = 0;
- static final int CALENDARS_INDEX_ACCOUNT_TYPE = 1;
- static final int CALENDARS_INDEX_CALENDAR_COLOR = 2;
-
- static final String[] COLORS_PROJECTION = new String[] {
- Colors.COLOR,
- Colors.COLOR_KEY
- };
-
- static final String COLORS_WHERE = Colors.ACCOUNT_NAME + "=? AND " + Colors.ACCOUNT_TYPE +
- "=? AND " + Colors.COLOR_TYPE + "=" + Colors.TYPE_CALENDAR;
-
- public static final int COLORS_INDEX_COLOR = 0;
- public static final int COLORS_INDEX_COLOR_KEY = 1;
-
-
- private QueryService mService;
- private SparseIntArray mColorKeyMap = new SparseIntArray();
- private long mCalendarId;
-
- private class QueryService extends AsyncQueryService {
-
- private QueryService(Context context) {
- super(context);
- }
-
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- // If the query didn't return a cursor for some reason return
- if (cursor == null) {
- return;
- }
-
- // If the Activity is finishing, then close the cursor.
- // Otherwise, use the new cursor in the adapter.
- final Activity activity = getActivity();
- if (activity == null || activity.isFinishing()) {
- cursor.close();
- return;
- }
-
- switch (token) {
- case TOKEN_QUERY_CALENDARS:
- if (!cursor.moveToFirst()) {
- cursor.close();
- dismiss();
- break;
- }
- mSelectedColor = Utils.getDisplayColorFromColor(
- cursor.getInt(CALENDARS_INDEX_CALENDAR_COLOR));
- Uri uri = Colors.CONTENT_URI;
- String[] args = new String[] {
- cursor.getString(CALENDARS_INDEX_ACCOUNT_NAME),
- cursor.getString(CALENDARS_INDEX_ACCOUNT_TYPE) };
- cursor.close();
- startQuery(TOKEN_QUERY_COLORS, null, uri, COLORS_PROJECTION, COLORS_WHERE,
- args, null);
- break;
- case TOKEN_QUERY_COLORS:
- if (!cursor.moveToFirst()) {
- cursor.close();
- dismiss();
- break;
- }
- mColorKeyMap.clear();
- ArrayList<Integer> colors = new ArrayList<Integer>();
- do
- {
- int colorKey = cursor.getInt(COLORS_INDEX_COLOR_KEY);
- int rawColor = cursor.getInt(COLORS_INDEX_COLOR);
- int displayColor = Utils.getDisplayColorFromColor(rawColor);
- mColorKeyMap.put(displayColor, colorKey);
- colors.add(displayColor);
- } while (cursor.moveToNext());
- Integer[] colorsToSort = colors.toArray(new Integer[colors.size()]);
- Arrays.sort(colorsToSort, new HsvColorComparator());
- mColors = new int[colorsToSort.length];
- for (int i = 0; i < mColors.length; i++) {
- mColors[i] = colorsToSort[i];
- }
- showPaletteView();
- cursor.close();
- break;
- }
- }
- }
-
- private class OnCalendarColorSelectedListener implements OnColorSelectedListener {
-
- @Override
- public void onColorSelected(int color) {
- if (color == mSelectedColor || mService == null) {
- return;
- }
-
- ContentValues values = new ContentValues();
- values.put(Calendars.CALENDAR_COLOR_KEY, mColorKeyMap.get(color));
- mService.startUpdate(mService.getNextToken(), null, ContentUris.withAppendedId(
- Calendars.CONTENT_URI, mCalendarId), values, null, null, Utils.UNDO_DELAY);
- }
- }
-
- public CalendarColorPickerDialog() {
- // Empty constructor required for dialog fragments.
- }
-
- public static CalendarColorPickerDialog newInstance(long calendarId, boolean isTablet) {
- CalendarColorPickerDialog ret = new CalendarColorPickerDialog();
- ret.setArguments(R.string.calendar_color_picker_dialog_title, NUM_COLUMNS,
- isTablet ? SIZE_LARGE : SIZE_SMALL);
- ret.setCalendarId(calendarId);
- return ret;
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putLong(KEY_CALENDAR_ID, mCalendarId);
- saveColorKeys(outState);
- }
-
- private void saveColorKeys(Bundle outState) {
- // No color keys to save, so just return
- if (mColors == null) {
- return;
- }
- int[] colorKeys = new int[mColors.length];
- for (int i = 0; i < mColors.length; i++) {
- colorKeys[i] = mColorKeyMap.get(mColors[i]);
- }
- outState.putIntArray(KEY_COLOR_KEYS, colorKeys);
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (savedInstanceState != null) {
- mCalendarId = savedInstanceState.getLong(KEY_CALENDAR_ID);
- retrieveColorKeys(savedInstanceState);
- }
- setOnColorSelectedListener(new OnCalendarColorSelectedListener());
- }
-
- private void retrieveColorKeys(Bundle savedInstanceState) {
- int[] colorKeys = savedInstanceState.getIntArray(KEY_COLOR_KEYS);
- if (mColors != null && colorKeys != null) {
- for (int i = 0; i < mColors.length; i++) {
- mColorKeyMap.put(mColors[i], colorKeys[i]);
- }
- }
- }
-
- @Override
- public void setColors(int[] colors) {
- throw new IllegalStateException("Must call setCalendarId() to update calendar colors");
- }
-
- @Override
- public void setColors(int[] colors, int selectedColor) {
- throw new IllegalStateException("Must call setCalendarId() to update calendar colors");
- }
-
- public void setCalendarId(long calendarId) {
- if (calendarId != mCalendarId) {
- mCalendarId = calendarId;
- startQuery();
- }
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- Dialog dialog = super.onCreateDialog(savedInstanceState);
- mService = new QueryService(getActivity());
- if (mColors == null) {
- startQuery();
- }
- return dialog;
- }
-
- private void startQuery() {
- if (mService != null) {
- showProgressBarView();
- mService.startQuery(TOKEN_QUERY_CALENDARS, null,
- ContentUris.withAppendedId(Calendars.CONTENT_URI, mCalendarId),
- CALENDARS_PROJECTION, null, null, null);
- }
- }
-}
diff --git a/src/com/android/calendar/CalendarController.java b/src/com/android/calendar/CalendarController.java
index 93b1b489..37286f2e 100644
--- a/src/com/android/calendar/CalendarController.java
+++ b/src/com/android/calendar/CalendarController.java
@@ -24,8 +24,6 @@ import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
-import android.app.SearchManager;
-import android.app.SearchableInfo;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentUris;
@@ -40,9 +38,6 @@ import android.text.format.Time;
import android.util.Log;
import android.util.Pair;
-import com.android.calendar.event.EditEventActivity;
-import com.android.calendar.selectcalendars.SelectVisibleCalendarsActivity;
-
import java.lang.ref.WeakReference;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -98,8 +93,6 @@ public class CalendarController {
* One of the event types that are sent to or from the controller
*/
public interface EventType {
- final long CREATE_EVENT = 1L;
-
// Simple view of an event
final long VIEW_EVENT = 1L << 1;
@@ -109,24 +102,14 @@ public class CalendarController {
// full detail view in edit mode
final long EDIT_EVENT = 1L << 3;
- final long DELETE_EVENT = 1L << 4;
-
final long GO_TO = 1L << 5;
- final long LAUNCH_SETTINGS = 1L << 6;
-
final long EVENTS_CHANGED = 1L << 7;
- final long SEARCH = 1L << 8;
-
- // User has pressed the home key
final long USER_HOME = 1L << 9;
// date range has changed, update the title
final long UPDATE_TITLE = 1L << 10;
-
- // select which calendars to display
- final long LAUNCH_SELECT_VISIBLE_CALENDARS = 1L << 11;
}
/**
@@ -178,9 +161,6 @@ public class CalendarController {
* To signal the event is an all-day event, "or" ALL_DAY_MASK with the response.
* Alternatively, use buildViewExtraLong(), getResponse(), and isAllDay().
* <p>
- * For EventType.CREATE_EVENT:
- * Set to {@link #EXTRA_CREATE_ALL_DAY} for creating an all-day event.
- * <p>
* For EventType.GO_TO:
* Set to {@link #EXTRA_GOTO_TIME} to go to the specified date/time.
* Set to {@link #EXTRA_GOTO_DATE} to consider the date but ignore the time.
@@ -249,12 +229,6 @@ public class CalendarController {
}
/**
- * Pass to the ExtraLong parameter for EventType.CREATE_EVENT to create
- * an all-day event
- */
- public static final long EXTRA_CREATE_ALL_DAY = 0x10;
-
- /**
* Pass to the ExtraLong parameter for EventType.GO_TO to signal the time
* can be ignored
*/
@@ -367,7 +341,7 @@ public class CalendarController {
long selectedMillis, String title, long calendarId) {
EventInfo info = new EventInfo();
info.eventType = eventType;
- if (eventType == EventType.EDIT_EVENT || eventType == EventType.VIEW_EVENT_DETAILS) {
+ if (eventType == EventType.VIEW_EVENT_DETAILS) {
info.viewType = ViewType.CURRENT;
}
@@ -509,7 +483,7 @@ public class CalendarController {
// Store the eventId if we're entering edit event
if ((event.eventType
- & (EventType.CREATE_EVENT | EventType.EDIT_EVENT | EventType.VIEW_EVENT_DETAILS))
+ & (EventType.VIEW_EVENT_DETAILS))
!= 0) {
if (event.id > 0) {
mEventId = event.id;
@@ -580,45 +554,6 @@ public class CalendarController {
}
}
}
-
- if (!handled) {
- // Launch Settings
- if (event.eventType == EventType.LAUNCH_SETTINGS) {
- launchSettings();
- return;
- }
-
- // Launch Calendar Visible Selector
- if (event.eventType == EventType.LAUNCH_SELECT_VISIBLE_CALENDARS) {
- launchSelectVisibleCalendars();
- return;
- }
-
- // Create/View/Edit/Delete Event
- long endTime = (event.endTime == null) ? -1 : event.endTime.toMillis(false);
- if (event.eventType == EventType.CREATE_EVENT) {
- launchCreateEvent(event.startTime.toMillis(false), endTime,
- event.extraLong == EXTRA_CREATE_ALL_DAY, event.eventTitle,
- event.calendarId);
- return;
- } else if (event.eventType == EventType.VIEW_EVENT) {
- launchViewEvent(event.id, event.startTime.toMillis(false), endTime,
- event.getResponse());
- return;
- } else if (event.eventType == EventType.EDIT_EVENT) {
- launchEditEvent(event.id, event.startTime.toMillis(false), endTime, true);
- return;
- } else if (event.eventType == EventType.VIEW_EVENT_DETAILS) {
- launchEditEvent(event.id, event.startTime.toMillis(false), endTime, false);
- return;
- } else if (event.eventType == EventType.DELETE_EVENT) {
- launchDeleteEvent(event.id, event.startTime.toMillis(false), endTime);
- return;
- } else if (event.eventType == EventType.SEARCH) {
- launchSearch(event.id, event.query, event.componentName);
- return;
- }
- }
}
/**
@@ -719,40 +654,6 @@ public class CalendarController {
return mPreviousViewType;
}
- private void launchSelectVisibleCalendars() {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setClass(mContext, SelectVisibleCalendarsActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
- mContext.startActivity(intent);
- }
-
- private void launchSettings() {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setClass(mContext, CalendarSettingsActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
- mContext.startActivity(intent);
- }
-
- private void launchCreateEvent(long startMillis, long endMillis, boolean allDayEvent,
- String title, long calendarId) {
- Intent intent = generateCreateEventIntent(startMillis, endMillis, allDayEvent, title,
- calendarId);
- mEventId = -1;
- mContext.startActivity(intent);
- }
-
- public Intent generateCreateEventIntent(long startMillis, long endMillis,
- boolean allDayEvent, String title, long calendarId) {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setClass(mContext, EditEventActivity.class);
- intent.putExtra(EXTRA_EVENT_BEGIN_TIME, startMillis);
- intent.putExtra(EXTRA_EVENT_END_TIME, endMillis);
- intent.putExtra(EXTRA_EVENT_ALL_DAY, allDayEvent);
- intent.putExtra(Events.CALENDAR_ID, calendarId);
- intent.putExtra(Events.TITLE, title);
- return intent;
- }
-
public void launchViewEvent(long eventId, long startMillis, long endMillis, int response) {
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri eventUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId);
@@ -765,64 +666,6 @@ public class CalendarController {
mContext.startActivity(intent);
}
- private void launchEditEvent(long eventId, long startMillis, long endMillis, boolean edit) {
- Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId);
- Intent intent = new Intent(Intent.ACTION_EDIT, uri);
- intent.putExtra(EXTRA_EVENT_BEGIN_TIME, startMillis);
- intent.putExtra(EXTRA_EVENT_END_TIME, endMillis);
- intent.setClass(mContext, EditEventActivity.class);
- intent.putExtra(EVENT_EDIT_ON_LAUNCH, edit);
- mEventId = eventId;
- mContext.startActivity(intent);
- }
-
-// private void launchAlerts() {
-// Intent intent = new Intent();
-// intent.setClass(mContext, AlertActivity.class);
-// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-// mContext.startActivity(intent);
-// }
-
- private void launchDeleteEvent(long eventId, long startMillis, long endMillis) {
- launchDeleteEventAndFinish(null, eventId, startMillis, endMillis, -1);
- }
-
- private void launchDeleteEventAndFinish(Activity parentActivity, long eventId, long startMillis,
- long endMillis, int deleteWhich) {
- DeleteEventHelper deleteEventHelper = new DeleteEventHelper(mContext, parentActivity,
- parentActivity != null /* exit when done */);
- deleteEventHelper.delete(startMillis, endMillis, eventId, deleteWhich);
- }
-
- private void launchSearch(long eventId, String query, ComponentName componentName) {
- final SearchManager searchManager =
- (SearchManager)mContext.getSystemService(Context.SEARCH_SERVICE);
- final SearchableInfo searchableInfo = searchManager.getSearchableInfo(componentName);
- final Intent intent = new Intent(Intent.ACTION_SEARCH);
- intent.putExtra(SearchManager.QUERY, query);
- intent.setComponent(searchableInfo.getSearchActivity());
- intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
- mContext.startActivity(intent);
- }
-
- /**
- * Performs a manual refresh of calendars in all known accounts.
- */
- public void refreshCalendars() {
- Account[] accounts = AccountManager.get(mContext).getAccounts();
- Log.d(TAG, "Refreshing " + accounts.length + " accounts");
-
- String authority = Calendars.CONTENT_URI.getAuthority();
- for (int i = 0; i < accounts.length; i++) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Refreshing calendars for: " + accounts[i]);
- }
- Bundle extras = new Bundle();
- extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
- ContentResolver.requestSync(accounts[i], authority, extras);
- }
- }
-
// Forces the viewType. Should only be used for initialization.
public void setViewType(int viewType) {
mViewType = viewType;
@@ -839,24 +682,12 @@ public class CalendarController {
StringBuilder builder = new StringBuilder();
if ((eventInfo.eventType & EventType.GO_TO) != 0) {
tmp = "Go to time/event";
- } else if ((eventInfo.eventType & EventType.CREATE_EVENT) != 0) {
- tmp = "New event";
} else if ((eventInfo.eventType & EventType.VIEW_EVENT) != 0) {
tmp = "View event";
} else if ((eventInfo.eventType & EventType.VIEW_EVENT_DETAILS) != 0) {
tmp = "View details";
- } else if ((eventInfo.eventType & EventType.EDIT_EVENT) != 0) {
- tmp = "Edit event";
- } else if ((eventInfo.eventType & EventType.DELETE_EVENT) != 0) {
- tmp = "Delete event";
- } else if ((eventInfo.eventType & EventType.LAUNCH_SELECT_VISIBLE_CALENDARS) != 0) {
- tmp = "Launch select visible calendars";
- } else if ((eventInfo.eventType & EventType.LAUNCH_SETTINGS) != 0) {
- tmp = "Launch settings";
} else if ((eventInfo.eventType & EventType.EVENTS_CHANGED) != 0) {
tmp = "Refresh events";
- } else if ((eventInfo.eventType & EventType.SEARCH) != 0) {
- tmp = "Search";
} else if ((eventInfo.eventType & EventType.USER_HOME) != 0) {
tmp = "Gone home";
} else if ((eventInfo.eventType & EventType.UPDATE_TITLE) != 0) {
diff --git a/src/com/android/calendar/CalendarEventModel.java b/src/com/android/calendar/CalendarEventModel.java
deleted file mode 100644
index 8f6507e0..00000000
--- a/src/com/android/calendar/CalendarEventModel.java
+++ /dev/null
@@ -1,944 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.calendar;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.provider.CalendarContract.Attendees;
-import android.provider.CalendarContract.Calendars;
-import android.provider.CalendarContract.Events;
-import android.provider.CalendarContract.Reminders;
-import android.text.TextUtils;
-import android.text.util.Rfc822Token;
-
-import com.android.calendar.event.EditEventHelper;
-import com.android.calendar.event.EventColorCache;
-import com.android.common.Rfc822Validator;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.TimeZone;
-
-/**
- * Stores all the information needed to fill out an entry in the events table.
- * This is a convenient way for storing information needed by the UI to write to
- * the events table. Only fields that are important to the UI are included.
- */
-public class CalendarEventModel implements Serializable {
- private static final String TAG = "CalendarEventModel";
-
- public static class Attendee implements Serializable {
- @Override
- public int hashCode() {
- return (mEmail == null) ? 0 : mEmail.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof Attendee)) {
- return false;
- }
- Attendee other = (Attendee) obj;
- if (!TextUtils.equals(mEmail, other.mEmail)) {
- return false;
- }
- return true;
- }
-
- String getDisplayName() {
- if (TextUtils.isEmpty(mName)) {
- return mEmail;
- } else {
- return mName;
- }
- }
-
- public String mName;
- public String mEmail;
- public int mStatus;
- public String mIdentity;
- public String mIdNamespace;
-
- public Attendee(String name, String email) {
- this(name, email, Attendees.ATTENDEE_STATUS_NONE, null, null);
- }
- public Attendee(String name, String email, int status, String identity,
- String idNamespace) {
- mName = name;
- mEmail = email;
- mStatus = status;
- mIdentity = identity;
- mIdNamespace = idNamespace;
- }
- }
-
- /**
- * A single reminder entry.
- *
- * Instances of the class are immutable.
- */
- public static class ReminderEntry implements Comparable<ReminderEntry>, Serializable {
- private final int mMinutes;
- private final int mMethod;
-
- /**
- * Returns a new ReminderEntry, with the specified minutes and method.
- *
- * @param minutes Number of minutes before the start of the event that the alert will fire.
- * @param method Type of alert ({@link Reminders#METHOD_ALERT}, etc).
- */
- public static ReminderEntry valueOf(int minutes, int method) {
- // TODO: cache common instances
- return new ReminderEntry(minutes, method);
- }
-
- /**
- * Returns a ReminderEntry, with the specified number of minutes and a default alert method.
- *
- * @param minutes Number of minutes before the start of the event that the alert will fire.
- */
- public static ReminderEntry valueOf(int minutes) {
- return valueOf(minutes, Reminders.METHOD_DEFAULT);
- }
-
- /**
- * Constructs a new ReminderEntry.
- *
- * @param minutes Number of minutes before the start of the event that the alert will fire.
- * @param method Type of alert ({@link Reminders#METHOD_ALERT}, etc).
- */
- private ReminderEntry(int minutes, int method) {
- // TODO: error-check args
- mMinutes = minutes;
- mMethod = method;
- }
-
- @Override
- public int hashCode() {
- return mMinutes * 10 + mMethod;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof ReminderEntry)) {
- return false;
- }
-
- ReminderEntry re = (ReminderEntry) obj;
-
- if (re.mMinutes != mMinutes) {
- return false;
- }
-
- // Treat ALERT and DEFAULT as equivalent. This is useful during the "has anything
- // "changed" test, so that if DEFAULT is present, but we don't change anything,
- // the internal conversion of DEFAULT to ALERT doesn't force a database update.
- return re.mMethod == mMethod ||
- (re.mMethod == Reminders.METHOD_DEFAULT && mMethod == Reminders.METHOD_ALERT) ||
- (re.mMethod == Reminders.METHOD_ALERT && mMethod == Reminders.METHOD_DEFAULT);
- }
-
- @Override
- public String toString() {
- return "ReminderEntry min=" + mMinutes + " meth=" + mMethod;
- }
-
- /**
- * Comparison function for a sort ordered primarily descending by minutes,
- * secondarily ascending by method type.
- */
- @Override
- public int compareTo(ReminderEntry re) {
- if (re.mMinutes != mMinutes) {
- return re.mMinutes - mMinutes;
- }
- if (re.mMethod != mMethod) {
- return mMethod - re.mMethod;
- }
- return 0;
- }
-
- /** Returns the minutes. */
- public int getMinutes() {
- return mMinutes;
- }
-
- /** Returns the alert method. */
- public int getMethod() {
- return mMethod;
- }
- }
-
- // TODO strip out fields that don't ever get used
- /**
- * The uri of the event in the db. This should only be null for new events.
- */
- public String mUri = null;
- public long mId = -1;
- public long mCalendarId = -1;
- public String mCalendarDisplayName = ""; // Make sure this is in sync with the mCalendarId
- private int mCalendarColor = -1;
- private boolean mCalendarColorInitialized = false;
- public String mCalendarAccountName;
- public String mCalendarAccountType;
- public int mCalendarMaxReminders;
- public String mCalendarAllowedReminders;
- public String mCalendarAllowedAttendeeTypes;
- public String mCalendarAllowedAvailability;
-
- public String mSyncId = null;
- public String mSyncAccount = null;
- public String mSyncAccountType = null;
-
- public EventColorCache mEventColorCache;
- private int mEventColor = -1;
- private boolean mEventColorInitialized = false;
-
- // PROVIDER_NOTES owner account comes from the calendars table
- public String mOwnerAccount = null;
- public String mTitle = null;
- public String mLocation = null;
- public String mDescription = null;
- public String mRrule = null;
- public String mOrganizer = null;
- public String mOrganizerDisplayName = null;
- /**
- * Read-Only - Derived from other fields
- */
- public boolean mIsOrganizer = true;
- public boolean mIsFirstEventInSeries = true;
-
- // This should be set the same as mStart when created and is used for making changes to
- // recurring events. It should not be updated after it is initially set.
- public long mOriginalStart = -1;
- public long mStart = -1;
-
- // This should be set the same as mEnd when created and is used for making changes to
- // recurring events. It should not be updated after it is initially set.
- public long mOriginalEnd = -1;
- public long mEnd = -1;
- public String mDuration = null;
- public String mTimezone = null;
- public String mTimezone2 = null;
- public boolean mAllDay = false;
- public boolean mHasAlarm = false;
- public int mAvailability = Events.AVAILABILITY_BUSY;
-
- // PROVIDER_NOTES How does an event not have attendee data? The owner is added
- // as an attendee by default.
- public boolean mHasAttendeeData = true;
- public int mSelfAttendeeStatus = -1;
- public int mOwnerAttendeeId = -1;
- public String mOriginalSyncId = null;
- public long mOriginalId = -1;
- public Long mOriginalTime = null;
- public Boolean mOriginalAllDay = null;
- public boolean mGuestsCanModify = false;
- public boolean mGuestsCanInviteOthers = false;
- public boolean mGuestsCanSeeGuests = false;
-
- public boolean mOrganizerCanRespond = false;
- public int mCalendarAccessLevel = Calendars.CAL_ACCESS_CONTRIBUTOR;
-
- public int mEventStatus = Events.STATUS_CONFIRMED;
-
- // The model can't be updated with a calendar cursor until it has been
- // updated with an event cursor.
- public boolean mModelUpdatedWithEventCursor;
-
- public int mAccessLevel = 0;
- public ArrayList<ReminderEntry> mReminders;
- public ArrayList<ReminderEntry> mDefaultReminders;
-
- // PROVIDER_NOTES Using EditEventHelper the owner should not be included in this
- // list and will instead be added by saveEvent. Is this what we want?
- public LinkedHashMap<String, Attendee> mAttendeesList;
-
- public CalendarEventModel() {
- mReminders = new ArrayList<ReminderEntry>();
- mDefaultReminders = new ArrayList<ReminderEntry>();
- mAttendeesList = new LinkedHashMap<String, Attendee>();
- mTimezone = TimeZone.getDefault().getID();
- }
-
- public CalendarEventModel(Context context) {
- this();
-
- mTimezone = Utils.getTimeZone(context, null);
- SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
-
- String defaultReminder = prefs.getString(
- GeneralPreferences.KEY_DEFAULT_REMINDER, GeneralPreferences.NO_REMINDER_STRING);
- int defaultReminderMins = Integer.parseInt(defaultReminder);
- if (defaultReminderMins != GeneralPreferences.NO_REMINDER) {
- // Assume all calendars allow at least one reminder.
- mHasAlarm = true;
- mReminders.add(ReminderEntry.valueOf(defaultReminderMins));
- mDefaultReminders.add(ReminderEntry.valueOf(defaultReminderMins));
- }
- }
-
- public CalendarEventModel(Context context, Intent intent) {
- this(context);
-
- if (intent == null) {
- return;
- }
-
- String title = intent.getStringExtra(Events.TITLE);
- if (title != null) {
- mTitle = title;
- }
-
- String location = intent.getStringExtra(Events.EVENT_LOCATION);
- if (location != null) {
- mLocation = location;
- }
-
- String description = intent.getStringExtra(Events.DESCRIPTION);
- if (description != null) {
- mDescription = description;
- }
-
- int availability = intent.getIntExtra(Events.AVAILABILITY, -1);
- if (availability != -1) {
- mAvailability = availability;
- }
-
- int accessLevel = intent.getIntExtra(Events.ACCESS_LEVEL, -1);
- if (accessLevel != -1) {
- if (accessLevel > 0) {
- // TODO remove this if we add support for
- // Events.ACCESS_CONFIDENTIAL
- accessLevel--;
- }
- mAccessLevel = accessLevel;
- }
-
- String rrule = intent.getStringExtra(Events.RRULE);
- if (!TextUtils.isEmpty(rrule)) {
- mRrule = rrule;
- }
-
- String emails = intent.getStringExtra(Intent.EXTRA_EMAIL);
- if (!TextUtils.isEmpty(emails)) {
- String[] emailArray = emails.split("[ ,;]");
- for (String email : emailArray) {
- if (!TextUtils.isEmpty(email) && email.contains("@")) {
- email = email.trim();
- if (!mAttendeesList.containsKey(email)) {
- mAttendeesList.put(email, new Attendee("", email));
- }
- }
- }
- }
- }
-
- public boolean isValid() {
- if (mCalendarId == -1) {
- return false;
- }
- if (TextUtils.isEmpty(mOwnerAccount)) {
- return false;
- }
- return true;
- }
-
- public boolean isEmpty() {
- if (mTitle != null && mTitle.trim().length() > 0) {
- return false;
- }
-
- if (mLocation != null && mLocation.trim().length() > 0) {
- return false;
- }
-
- if (mDescription != null && mDescription.trim().length() > 0) {
- return false;
- }
-
- return true;
- }
-
- public void clear() {
- mUri = null;
- mId = -1;
- mCalendarId = -1;
- mCalendarColor = -1;
- mCalendarColorInitialized = false;
-
- mEventColorCache = null;
- mEventColor = -1;
- mEventColorInitialized = false;
-
- mSyncId = null;
- mSyncAccount = null;
- mSyncAccountType = null;
- mOwnerAccount = null;
-
- mTitle = null;
- mLocation = null;
- mDescription = null;
- mRrule = null;
- mOrganizer = null;
- mOrganizerDisplayName = null;
- mIsOrganizer = true;
- mIsFirstEventInSeries = true;
-
- mOriginalStart = -1;
- mStart = -1;
- mOriginalEnd = -1;
- mEnd = -1;
- mDuration = null;
- mTimezone = null;
- mTimezone2 = null;
- mAllDay = false;
- mHasAlarm = false;
-
- mHasAttendeeData = true;
- mSelfAttendeeStatus = -1;
- mOwnerAttendeeId = -1;
- mOriginalId = -1;
- mOriginalSyncId = null;
- mOriginalTime = null;
- mOriginalAllDay = null;
-
- mGuestsCanModify = false;
- mGuestsCanInviteOthers = false;
- mGuestsCanSeeGuests = false;
- mAccessLevel = 0;
- mEventStatus = Events.STATUS_CONFIRMED;
- mOrganizerCanRespond = false;
- mCalendarAccessLevel = Calendars.CAL_ACCESS_CONTRIBUTOR;
- mModelUpdatedWithEventCursor = false;
- mCalendarAllowedReminders = null;
- mCalendarAllowedAttendeeTypes = null;
- mCalendarAllowedAvailability = null;
-
- mReminders = new ArrayList<ReminderEntry>();
- mAttendeesList.clear();
- }
-
- public void addAttendee(Attendee attendee) {
- mAttendeesList.put(attendee.mEmail, attendee);
- }
-
- public void addAttendees(String attendees, Rfc822Validator validator) {
- final LinkedHashSet<Rfc822Token> addresses = EditEventHelper.getAddressesFromList(
- attendees, validator);
- synchronized (this) {
- for (final Rfc822Token address : addresses) {
- final Attendee attendee = new Attendee(address.getName(), address.getAddress());
- if (TextUtils.isEmpty(attendee.mName)) {
- attendee.mName = attendee.mEmail;
- }
- addAttendee(attendee);
- }
- }
- }
-
- public void removeAttendee(Attendee attendee) {
- mAttendeesList.remove(attendee.mEmail);
- }
-
- public String getAttendeesString() {
- StringBuilder b = new StringBuilder();
- for (Attendee attendee : mAttendeesList.values()) {
- String name = attendee.mName;
- String email = attendee.mEmail;
- String status = Integer.toString(attendee.mStatus);
- b.append("name:").append(name);
- b.append(" email:").append(email);
- b.append(" status:").append(status);
- }
- return b.toString();
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + (mAllDay ? 1231 : 1237);
- result = prime * result + ((mAttendeesList == null) ? 0 : getAttendeesString().hashCode());
- result = prime * result + (int) (mCalendarId ^ (mCalendarId >>> 32));
- result = prime * result + ((mDescription == null) ? 0 : mDescription.hashCode());
- result = prime * result + ((mDuration == null) ? 0 : mDuration.hashCode());
- result = prime * result + (int) (mEnd ^ (mEnd >>> 32));
- result = prime * result + (mGuestsCanInviteOthers ? 1231 : 1237);
- result = prime * result + (mGuestsCanModify ? 1231 : 1237);
- result = prime * result + (mGuestsCanSeeGuests ? 1231 : 1237);
- result = prime * result + (mOrganizerCanRespond ? 1231 : 1237);
- result = prime * result + (mModelUpdatedWithEventCursor ? 1231 : 1237);
- result = prime * result + mCalendarAccessLevel;
- result = prime * result + (mHasAlarm ? 1231 : 1237);
- result = prime * result + (mHasAttendeeData ? 1231 : 1237);
- result = prime * result + (int) (mId ^ (mId >>> 32));
- result = prime * result + (mIsFirstEventInSeries ? 1231 : 1237);
- result = prime * result + (mIsOrganizer ? 1231 : 1237);
- result = prime * result + ((mLocation == null) ? 0 : mLocation.hashCode());
- result = prime * result + ((mOrganizer == null) ? 0 : mOrganizer.hashCode());
- result = prime * result + ((mOriginalAllDay == null) ? 0 : mOriginalAllDay.hashCode());
- result = prime * result + (int) (mOriginalEnd ^ (mOriginalEnd >>> 32));
- result = prime * result + ((mOriginalSyncId == null) ? 0 : mOriginalSyncId.hashCode());
- result = prime * result + (int) (mOriginalId ^ (mOriginalEnd >>> 32));
- result = prime * result + (int) (mOriginalStart ^ (mOriginalStart >>> 32));
- result = prime * result + ((mOriginalTime == null) ? 0 : mOriginalTime.hashCode());
- result = prime * result + ((mOwnerAccount == null) ? 0 : mOwnerAccount.hashCode());
- result = prime * result + ((mReminders == null) ? 0 : mReminders.hashCode());
- result = prime * result + ((mRrule == null) ? 0 : mRrule.hashCode());
- result = prime * result + mSelfAttendeeStatus;
- result = prime * result + mOwnerAttendeeId;
- result = prime * result + (int) (mStart ^ (mStart >>> 32));
- result = prime * result + ((mSyncAccount == null) ? 0 : mSyncAccount.hashCode());
- result = prime * result + ((mSyncAccountType == null) ? 0 : mSyncAccountType.hashCode());
- result = prime * result + ((mSyncId == null) ? 0 : mSyncId.hashCode());
- result = prime * result + ((mTimezone == null) ? 0 : mTimezone.hashCode());
- result = prime * result + ((mTimezone2 == null) ? 0 : mTimezone2.hashCode());
- result = prime * result + ((mTitle == null) ? 0 : mTitle.hashCode());
- result = prime * result + (mAvailability);
- result = prime * result + ((mUri == null) ? 0 : mUri.hashCode());
- result = prime * result + mAccessLevel;
- result = prime * result + mEventStatus;
- return result;
- }
-
- // Autogenerated equals method
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (!(obj instanceof CalendarEventModel)) {
- return false;
- }
-
- CalendarEventModel other = (CalendarEventModel) obj;
- if (!checkOriginalModelFields(other)) {
- return false;
- }
-
- if (mLocation == null) {
- if (other.mLocation != null) {
- return false;
- }
- } else if (!mLocation.equals(other.mLocation)) {
- return false;
- }
-
- if (mTitle == null) {
- if (other.mTitle != null) {
- return false;
- }
- } else if (!mTitle.equals(other.mTitle)) {
- return false;
- }
-
- if (mDescription == null) {
- if (other.mDescription != null) {
- return false;
- }
- } else if (!mDescription.equals(other.mDescription)) {
- return false;
- }
-
- if (mDuration == null) {
- if (other.mDuration != null) {
- return false;
- }
- } else if (!mDuration.equals(other.mDuration)) {
- return false;
- }
-
- if (mEnd != other.mEnd) {
- return false;
- }
- if (mIsFirstEventInSeries != other.mIsFirstEventInSeries) {
- return false;
- }
- if (mOriginalEnd != other.mOriginalEnd) {
- return false;
- }
-
- if (mOriginalStart != other.mOriginalStart) {
- return false;
- }
- if (mStart != other.mStart) {
- return false;
- }
-
- if (mOriginalId != other.mOriginalId) {
- return false;
- }
-
- if (mOriginalSyncId == null) {
- if (other.mOriginalSyncId != null) {
- return false;
- }
- } else if (!mOriginalSyncId.equals(other.mOriginalSyncId)) {
- return false;
- }
-
- if (mRrule == null) {
- if (other.mRrule != null) {
- return false;
- }
- } else if (!mRrule.equals(other.mRrule)) {
- return false;
- }
- return true;
- }
-
- /**
- * Whether the event has been modified based on its original model.
- *
- * @param originalModel
- * @return true if the model is unchanged, false otherwise
- */
- public boolean isUnchanged(CalendarEventModel originalModel) {
- if (this == originalModel) {
- return true;
- }
- if (originalModel == null) {
- return false;
- }
-
- if (!checkOriginalModelFields(originalModel)) {
- return false;
- }
-
- if (TextUtils.isEmpty(mLocation)) {
- if (!TextUtils.isEmpty(originalModel.mLocation)) {
- return false;
- }
- } else if (!mLocation.equals(originalModel.mLocation)) {
- return false;
- }
-
- if (TextUtils.isEmpty(mTitle)) {
- if (!TextUtils.isEmpty(originalModel.mTitle)) {
- return false;
- }
- } else if (!mTitle.equals(originalModel.mTitle)) {
- return false;
- }
-
- if (TextUtils.isEmpty(mDescription)) {
- if (!TextUtils.isEmpty(originalModel.mDescription)) {
- return false;
- }
- } else if (!mDescription.equals(originalModel.mDescription)) {
- return false;
- }
-
- if (TextUtils.isEmpty(mDuration)) {
- if (!TextUtils.isEmpty(originalModel.mDuration)) {
- return false;
- }
- } else if (!mDuration.equals(originalModel.mDuration)) {
- return false;
- }
-
- if (mEnd != mOriginalEnd) {
- return false;
- }
- if (mStart != mOriginalStart) {
- return false;
- }
-
- // If this changed the original id and it's not just an exception to the
- // original event
- if (mOriginalId != originalModel.mOriginalId && mOriginalId != originalModel.mId) {
- return false;
- }
-
- if (TextUtils.isEmpty(mRrule)) {
- // if the rrule is no longer empty check if this is an exception
- if (!TextUtils.isEmpty(originalModel.mRrule)) {
- boolean syncIdNotReferenced = mOriginalSyncId == null
- || !mOriginalSyncId.equals(originalModel.mSyncId);
- boolean localIdNotReferenced = mOriginalId == -1
- || !(mOriginalId == originalModel.mId);
- if (syncIdNotReferenced && localIdNotReferenced) {
- return false;
- }
- }
- } else if (!mRrule.equals(originalModel.mRrule)) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Checks against an original model for changes to an event. This covers all
- * the fields that should remain consistent between an original event model
- * and the new one if nothing in the event was modified. This is also the
- * portion that overlaps with equality between two event models.
- *
- * @param originalModel
- * @return true if these fields are unchanged, false otherwise
- */
- protected boolean checkOriginalModelFields(CalendarEventModel originalModel) {
- if (mAllDay != originalModel.mAllDay) {
- return false;
- }
- if (mAttendeesList == null) {
- if (originalModel.mAttendeesList != null) {
- return false;
- }
- } else if (!mAttendeesList.equals(originalModel.mAttendeesList)) {
- return false;
- }
-
- if (mCalendarId != originalModel.mCalendarId) {
- return false;
- }
- if (mCalendarColor != originalModel.mCalendarColor) {
- return false;
- }
- if (mCalendarColorInitialized != originalModel.mCalendarColorInitialized) {
- return false;
- }
- if (mGuestsCanInviteOthers != originalModel.mGuestsCanInviteOthers) {
- return false;
- }
- if (mGuestsCanModify != originalModel.mGuestsCanModify) {
- return false;
- }
- if (mGuestsCanSeeGuests != originalModel.mGuestsCanSeeGuests) {
- return false;
- }
- if (mOrganizerCanRespond != originalModel.mOrganizerCanRespond) {
- return false;
- }
- if (mCalendarAccessLevel != originalModel.mCalendarAccessLevel) {
- return false;
- }
- if (mModelUpdatedWithEventCursor != originalModel.mModelUpdatedWithEventCursor) {
- return false;
- }
- if (mHasAlarm != originalModel.mHasAlarm) {
- return false;
- }
- if (mHasAttendeeData != originalModel.mHasAttendeeData) {
- return false;
- }
- if (mId != originalModel.mId) {
- return false;
- }
- if (mIsOrganizer != originalModel.mIsOrganizer) {
- return false;
- }
-
- if (mOrganizer == null) {
- if (originalModel.mOrganizer != null) {
- return false;
- }
- } else if (!mOrganizer.equals(originalModel.mOrganizer)) {
- return false;
- }
-
- if (mOriginalAllDay == null) {
- if (originalModel.mOriginalAllDay != null) {
- return false;
- }
- } else if (!mOriginalAllDay.equals(originalModel.mOriginalAllDay)) {
- return false;
- }
-
- if (mOriginalTime == null) {
- if (originalModel.mOriginalTime != null) {
- return false;
- }
- } else if (!mOriginalTime.equals(originalModel.mOriginalTime)) {
- return false;
- }
-
- if (mOwnerAccount == null) {
- if (originalModel.mOwnerAccount != null) {
- return false;
- }
- } else if (!mOwnerAccount.equals(originalModel.mOwnerAccount)) {
- return false;
- }
-
- if (mReminders == null) {
- if (originalModel.mReminders != null) {
- return false;
- }
- } else if (!mReminders.equals(originalModel.mReminders)) {
- return false;
- }
-
- if (mSelfAttendeeStatus != originalModel.mSelfAttendeeStatus) {
- return false;
- }
- if (mOwnerAttendeeId != originalModel.mOwnerAttendeeId) {
- return false;
- }
- if (mSyncAccount == null) {
- if (originalModel.mSyncAccount != null) {
- return false;
- }
- } else if (!mSyncAccount.equals(originalModel.mSyncAccount)) {
- return false;
- }
-
- if (mSyncAccountType == null) {
- if (originalModel.mSyncAccountType != null) {
- return false;
- }
- } else if (!mSyncAccountType.equals(originalModel.mSyncAccountType)) {
- return false;
- }
-
- if (mSyncId == null) {
- if (originalModel.mSyncId != null) {
- return false;
- }
- } else if (!mSyncId.equals(originalModel.mSyncId)) {
- return false;
- }
-
- if (mTimezone == null) {
- if (originalModel.mTimezone != null) {
- return false;
- }
- } else if (!mTimezone.equals(originalModel.mTimezone)) {
- return false;
- }
-
- if (mTimezone2 == null) {
- if (originalModel.mTimezone2 != null) {
- return false;
- }
- } else if (!mTimezone2.equals(originalModel.mTimezone2)) {
- return false;
- }
-
- if (mAvailability != originalModel.mAvailability) {
- return false;
- }
-
- if (mUri == null) {
- if (originalModel.mUri != null) {
- return false;
- }
- } else if (!mUri.equals(originalModel.mUri)) {
- return false;
- }
-
- if (mAccessLevel != originalModel.mAccessLevel) {
- return false;
- }
-
- if (mEventStatus != originalModel.mEventStatus) {
- return false;
- }
-
- if (mEventColor != originalModel.mEventColor) {
- return false;
- }
-
- if (mEventColorInitialized != originalModel.mEventColorInitialized) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Sort and uniquify mReminderMinutes.
- *
- * @return true (for convenience of caller)
- */
- public boolean normalizeReminders() {
- if (mReminders.size() <= 1) {
- return true;
- }
-
- // sort
- Collections.sort(mReminders);
-
- // remove duplicates
- ReminderEntry prev = mReminders.get(mReminders.size()-1);
- for (int i = mReminders.size()-2; i >= 0; --i) {
- ReminderEntry cur = mReminders.get(i);
- if (prev.equals(cur)) {
- // match, remove later entry
- mReminders.remove(i+1);
- }
- prev = cur;
- }
-
- return true;
- }
-
- public boolean isCalendarColorInitialized() {
- return mCalendarColorInitialized;
- }
-
- public boolean isEventColorInitialized() {
- return mEventColorInitialized;
- }
-
- public int getCalendarColor() {
- return mCalendarColor;
- }
-
- public int getEventColor() {
- return mEventColor;
- }
-
- public void setCalendarColor(int color) {
- mCalendarColor = color;
- mCalendarColorInitialized = true;
- }
-
- public void setEventColor(int color) {
- mEventColor = color;
- mEventColorInitialized = true;
- }
-
- public int[] getCalendarEventColors() {
- if (mEventColorCache != null) {
- return mEventColorCache.getColorArray(mCalendarAccountName, mCalendarAccountType);
- }
- return null;
- }
-
- public int getEventColorKey() {
- if (mEventColorCache != null) {
- return mEventColorCache.getColorKey(mCalendarAccountName, mCalendarAccountType,
- mEventColor);
- }
- return -1;
- }
-}
diff --git a/src/com/android/calendar/CalendarRecentSuggestionsProvider.java b/src/com/android/calendar/CalendarRecentSuggestionsProvider.java
deleted file mode 100644
index 2e3deae7..00000000
--- a/src/com/android/calendar/CalendarRecentSuggestionsProvider.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.calendar;
-
-import android.content.SearchRecentSuggestionsProvider;
-
-public class CalendarRecentSuggestionsProvider extends SearchRecentSuggestionsProvider {
-
- public final static int MODE = DATABASE_MODE_QUERIES;
-
- public CalendarRecentSuggestionsProvider() {
- }
-
- @Override
- public boolean onCreate() {
- setupSuggestions(Utils.getSearchAuthority(getContext()), MODE);
- return super.onCreate();
- }
-
-}
diff --git a/src/com/android/calendar/CalendarSettingsActivity.java b/src/com/android/calendar/CalendarSettingsActivity.java
deleted file mode 100644
index a864b532..00000000
--- a/src/com/android/calendar/CalendarSettingsActivity.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.calendar;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.app.ActionBar;
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.preference.PreferenceActivity;
-import android.provider.CalendarContract;
-import android.provider.CalendarContract.Calendars;
-import android.provider.Settings;
-import android.text.format.DateUtils;
-import android.view.Menu;
-import android.view.MenuItem;
-
-import java.util.List;
-
-public class CalendarSettingsActivity extends PreferenceActivity {
- private static final int CHECK_ACCOUNTS_DELAY = 3000;
- private Account[] mAccounts;
- private Handler mHandler = new Handler();
- private boolean mHideMenuButtons = false;
-
- @Override
- public void onBuildHeaders(List<Header> target) {
- loadHeadersFromResource(R.xml.calendar_settings_headers, target);
-
- Account[] accounts = AccountManager.get(this).getAccounts();
- if (accounts != null) {
- int length = accounts.length;
- for (int i = 0; i < length; i++) {
- Account acct = accounts[i];
- if (ContentResolver.getIsSyncable(acct, CalendarContract.AUTHORITY) > 0) {
- Header accountHeader = new Header();
- accountHeader.title = acct.name;
- accountHeader.fragment =
- "com.android.calendar.selectcalendars.SelectCalendarsSyncFragment";
- Bundle args = new Bundle();
- args.putString(Calendars.ACCOUNT_NAME, acct.name);
- args.putString(Calendars.ACCOUNT_TYPE, acct.type);
- accountHeader.fragmentArguments = args;
- target.add(1, accountHeader);
- }
- }
- }
- mAccounts = accounts;
- if (Utils.getTardis() + DateUtils.MINUTE_IN_MILLIS > System.currentTimeMillis()) {
- Header tardisHeader = new Header();
- tardisHeader.title = getString(R.string.preferences_experimental_category);
- tardisHeader.fragment = "com.android.calendar.OtherPreferences";
- target.add(tardisHeader);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- finish();
- return true;
- } else if (item.getItemId() == R.id.action_add_account) {
- Intent nextIntent = new Intent(Settings.ACTION_ADD_ACCOUNT);
- final String[] array = { "com.android.calendar" };
- nextIntent.putExtra(Settings.EXTRA_AUTHORITIES, array);
- nextIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(nextIntent);
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- if (!mHideMenuButtons) {
- getMenuInflater().inflate(R.menu.settings_title_bar, menu);
- }
- getActionBar()
- .setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);
- return true;
- }
-
- @Override
- public void onResume() {
- if (mHandler != null) {
- mHandler.postDelayed(mCheckAccounts, CHECK_ACCOUNTS_DELAY);
- }
- super.onResume();
- }
-
- @Override
- public void onPause() {
- if (mHandler != null) {
- mHandler.removeCallbacks(mCheckAccounts);
- }
- super.onPause();
- }
-
- @Override
- protected boolean isValidFragment(String fragmentName) {
- // This activity is not exported so we can just approve everything
- return true;
- }
-
- Runnable mCheckAccounts = new Runnable() {
- @Override
- public void run() {
- Account[] accounts = AccountManager.get(CalendarSettingsActivity.this).getAccounts();
- if (accounts != null && !accounts.equals(mAccounts)) {
- invalidateHeaders();
- }
- }
- };
-
- public void hideMenuButtons() {
- mHideMenuButtons = true;
- }
-}
diff --git a/src/com/android/calendar/CalendarViewAdapter.java b/src/com/android/calendar/CalendarViewAdapter.java
index f07d4d8a..524268fc 100644
--- a/src/com/android/calendar/CalendarViewAdapter.java
+++ b/src/com/android/calendar/CalendarViewAdapter.java
@@ -198,11 +198,6 @@ public class CalendarViewAdapter extends BaseAdapter {
weekDay.setVisibility(View.GONE);
date.setText(buildMonthYearDate());
break;
- case ViewType.AGENDA:
- weekDay.setVisibility(View.VISIBLE);
- weekDay.setText(buildDayOfWeek());
- date.setText(buildFullDate());
- break;
default:
v = null;
break;
@@ -229,9 +224,6 @@ public class CalendarViewAdapter extends BaseAdapter {
case ViewType.MONTH:
title.setText(mButtonNames [MONTH_BUTTON_INDEX]);
break;
- case ViewType.AGENDA:
- title.setText(mButtonNames [AGENDA_BUTTON_INDEX]);
- break;
default:
v = null;
break;
@@ -280,12 +272,6 @@ public class CalendarViewAdapter extends BaseAdapter {
date.setText(buildMonthDate());
}
break;
- case AGENDA_BUTTON_INDEX:
- viewType.setText(mButtonNames [AGENDA_BUTTON_INDEX]);
- if (mShowDate) {
- date.setText(buildMonthDayDate());
- }
- break;
default:
v = convertView;
break;
@@ -379,9 +365,8 @@ public class CalendarViewAdapter extends BaseAdapter {
| DateUtils.FORMAT_NO_MONTH_DAY, mTimeZone).toString();
return date;
}
- private String buildWeekDate() {
-
+ private String buildWeekDate() {
// Calculate the start of the week, taking into account the "first day of the week"
// setting.
@@ -422,4 +407,3 @@ public class CalendarViewAdapter extends BaseAdapter {
}
}
-
diff --git a/src/com/android/calendar/CloudNotificationBackplane.java b/src/com/android/calendar/CloudNotificationBackplane.java
deleted file mode 100644
index d9ff0cc0..00000000
--- a/src/com/android/calendar/CloudNotificationBackplane.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2013 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 java.io.IOException;
-
-import android.content.Context;
-import android.os.Bundle;
-
-public interface CloudNotificationBackplane {
- public boolean open(Context context);
- public boolean subscribeToGroup(String senderId, String account, String groupId)
- throws IOException;
- public void send(String to, String msgId, Bundle data) throws IOException;
- public void close();
-}
diff --git a/src/com/android/calendar/ColorChipView.java b/src/com/android/calendar/ColorChipView.java
deleted file mode 100644
index daf0933a..00000000
--- a/src/com/android/calendar/ColorChipView.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2011 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.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Paint.Style;
-import android.util.AttributeSet;
-import android.view.View;
-
-
-
-
-/**
- * A custom view for a color chip for an event that can be drawn differently
- * accroding to the event's status.
- *
- */
-public class ColorChipView extends View {
-
- private static final String TAG = "ColorChipView";
- // Style of drawing
- // Full rectangle for accepted events
- // Border for tentative events
- // Cross-hatched with 50% transparency for declined events
-
- public static final int DRAW_FULL = 0;
- public static final int DRAW_BORDER = 1;
- public static final int DRAW_FADED = 2;
-
- private int mDrawStyle = DRAW_FULL;
- private float mDefStrokeWidth;
- private Paint mPaint;
-
- private static final int DEF_BORDER_WIDTH = 4;
-
- int mBorderWidth = DEF_BORDER_WIDTH;
-
- int mColor;
-
- public ColorChipView(Context context) {
- super(context);
- init();
- }
-
- public ColorChipView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- private void init() {
- mPaint = new Paint();
- mDefStrokeWidth = mPaint.getStrokeWidth();
- mPaint.setStyle(Style.FILL_AND_STROKE);
- }
-
-
- public void setDrawStyle(int style) {
- if (style != DRAW_FULL && style != DRAW_BORDER && style != DRAW_FADED) {
- return;
- }
- mDrawStyle = style;
- invalidate();
- }
-
- public void setBorderWidth(int width) {
- if (width >= 0) {
- mBorderWidth = width;
- invalidate();
- }
- }
-
- public void setColor(int color) {
- mColor = color;
- invalidate();
- }
-
- @Override
- public void onDraw(Canvas c) {
-
- int right = getWidth() - 1;
- int bottom = getHeight() - 1;
- mPaint.setColor(mDrawStyle == DRAW_FADED ?
- Utils.getDeclinedColorFromColor(mColor) : mColor);
-
- switch (mDrawStyle) {
- case DRAW_FADED:
- case DRAW_FULL:
- mPaint.setStrokeWidth(mDefStrokeWidth);
- c.drawRect(0, 0, right, bottom, mPaint);
- break;
- case DRAW_BORDER:
- if (mBorderWidth <= 0) {
- return;
- }
- int halfBorderWidth = mBorderWidth / 2;
- int top = halfBorderWidth;
- int left = halfBorderWidth;
- mPaint.setStrokeWidth(mBorderWidth);
-
- float[] lines = new float[16];
- int ptr = 0;
- lines [ptr++] = 0;
- lines [ptr++] = top;
- lines [ptr++] = right;
- lines [ptr++] = top;
- lines [ptr++] = 0;
- lines [ptr++] = bottom - halfBorderWidth;
- lines [ptr++] = right;
- lines [ptr++] = bottom - halfBorderWidth;
- lines [ptr++] = left;
- lines [ptr++] = 0;
- lines [ptr++] = left;
- lines [ptr++] = bottom;
- lines [ptr++] = right - halfBorderWidth;
- lines [ptr++] = 0;
- lines [ptr++] = right - halfBorderWidth;
- lines [ptr++] = bottom;
- c.drawLines(lines, mPaint);
- break;
- }
- }
-}
diff --git a/src/com/android/calendar/ContactsAsyncHelper.java b/src/com/android/calendar/ContactsAsyncHelper.java
deleted file mode 100644
index b7e01dba..00000000
--- a/src/com/android/calendar/ContactsAsyncHelper.java
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright (C) 2008 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 com.android.calendar.event.EditEventHelper.AttendeeItem;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.ContactsContract.Contacts;
-import android.util.Log;
-import android.view.View;
-import android.widget.ImageView;
-
-import java.io.InputStream;
-
-/**
- * Helper class for async access of images.
- */
-public class ContactsAsyncHelper extends Handler {
-
- private static final boolean DBG = false;
- private static final String LOG_TAG = "ContactsAsyncHelper";
-
- private static ContactsAsyncHelper mInstance = null;
-
- /**
- * Interface for a WorkerHandler result return.
- */
- public interface OnImageLoadCompleteListener {
- /**
- * Called when the image load is complete.
- *
- * @param imagePresent true if an image was found
- */
- public void onImageLoadComplete(int token, Object cookie, ImageView iView,
- boolean imagePresent);
- }
-
- // constants
- private static final int EVENT_LOAD_IMAGE = 1;
- private static final int EVENT_LOAD_DRAWABLE = 2;
- private static final int DEFAULT_TOKEN = -1;
-
- // static objects
- private static Handler sThreadHandler;
-
- private static final class WorkerArgs {
- public Context context;
- public ImageView view;
- public Uri uri;
- public int defaultResource;
- public Object result;
- public AttendeeItem item;
- public Runnable callback;
- }
-
- /**
- * Thread worker class that handles the task of opening the stream and loading
- * the images.
- */
- private class WorkerHandler extends Handler {
- public WorkerHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- WorkerArgs args = (WorkerArgs) msg.obj;
-
- switch (msg.arg1) {
- case EVENT_LOAD_DRAWABLE:
- case EVENT_LOAD_IMAGE:
- InputStream inputStream = null;
- try {
- inputStream = Contacts.openContactPhotoInputStream(
- args.context.getContentResolver(), args.uri);
- } catch (Exception e) {
- Log.e(LOG_TAG, "Error opening photo input stream", e);
- }
-
- if (inputStream != null) {
- args.result = Drawable.createFromStream(inputStream, args.uri.toString());
-
- if (DBG) Log.d(LOG_TAG, "Loading image: " + msg.arg1 +
- " token: " + msg.what + " image URI: " + args.uri);
- } else {
- args.result = null;
- if (DBG) Log.d(LOG_TAG, "Problem with image: " + msg.arg1 +
- " token: " + msg.what + " image URI: " + args.uri +
- ", using default image.");
- }
- break;
- default:
- }
-
- // send the reply to the enclosing class.
- Message reply = ContactsAsyncHelper.this.obtainMessage(msg.what);
- reply.arg1 = msg.arg1;
- reply.obj = msg.obj;
- reply.sendToTarget();
- }
- }
-
- /**
- * Private constructor for static class
- */
- private ContactsAsyncHelper() {
- HandlerThread thread = new HandlerThread("ContactsAsyncWorker");
- thread.start();
- sThreadHandler = new WorkerHandler(thread.getLooper());
- }
-
- /**
- * Start an image load, attach the result to the specified CallerInfo object.
- * Note, when the query is started, we make the ImageView INVISIBLE if the
- * placeholderImageResource value is -1. When we're given a valid (!= -1)
- * placeholderImageResource value, we make sure the image is visible.
- */
- public static final void updateImageViewWithContactPhotoAsync(Context context,
- ImageView imageView, Uri contact, int placeholderImageResource) {
-
- // in case the source caller info is null, the URI will be null as well.
- // just update using the placeholder image in this case.
- if (contact == null) {
- if (DBG) Log.d(LOG_TAG, "target image is null, just display placeholder.");
- imageView.setVisibility(View.VISIBLE);
- imageView.setImageResource(placeholderImageResource);
- return;
- }
-
- // Added additional Cookie field in the callee to handle arguments
- // sent to the callback function.
-
- // setup arguments
- WorkerArgs args = new WorkerArgs();
- args.context = context;
- args.view = imageView;
- args.uri = contact;
- args.defaultResource = placeholderImageResource;
-
- if (mInstance == null) {
- mInstance = new ContactsAsyncHelper();
- }
- // setup message arguments
- Message msg = sThreadHandler.obtainMessage(DEFAULT_TOKEN);
- msg.arg1 = EVENT_LOAD_IMAGE;
- msg.obj = args;
-
- if (DBG) Log.d(LOG_TAG, "Begin loading image: " + args.uri +
- ", displaying default image for now.");
-
- // set the default image first, when the query is complete, we will
- // replace the image with the correct one.
- if (placeholderImageResource != -1) {
- imageView.setVisibility(View.VISIBLE);
- imageView.setImageResource(placeholderImageResource);
- } else {
- imageView.setVisibility(View.INVISIBLE);
- }
-
- // notify the thread to begin working
- sThreadHandler.sendMessage(msg);
- }
-
- /**
- * Start an image load, attach the result to the specified CallerInfo object.
- * Note, when the query is started, we make the ImageView INVISIBLE if the
- * placeholderImageResource value is -1. When we're given a valid (!= -1)
- * placeholderImageResource value, we make sure the image is visible.
- */
- public static final void retrieveContactPhotoAsync(Context context,
- AttendeeItem item, Runnable run, Uri photoUri) {
-
- // in case the source caller info is null, the URI will be null as well.
- // just return as there's nothing to do.
- if (photoUri == null) {
- return;
- }
-
- // Added additional Cookie field in the callee to handle arguments
- // sent to the callback function.
-
- // setup arguments
- WorkerArgs args = new WorkerArgs();
- args.context = context;
- args.item = item;
- args.uri = photoUri;
- args.callback = run;
-
- if (mInstance == null) {
- mInstance = new ContactsAsyncHelper();
- }
- // setup message arguments
- Message msg = sThreadHandler.obtainMessage(DEFAULT_TOKEN);
- msg.arg1 = EVENT_LOAD_DRAWABLE;
- msg.obj = args;
-
- if (DBG) Log.d(LOG_TAG, "Begin loading drawable: " + args.uri);
-
-
- // notify the thread to begin working
- sThreadHandler.sendMessage(msg);
- }
-
- /**
- * Called when loading is done.
- */
- @Override
- public void handleMessage(Message msg) {
- WorkerArgs args = (WorkerArgs) msg.obj;
- switch (msg.arg1) {
- case EVENT_LOAD_IMAGE:
- // if the image has been loaded then display it, otherwise set default.
- // in either case, make sure the image is visible.
- if (args.result != null) {
- args.view.setVisibility(View.VISIBLE);
- args.view.setImageDrawable((Drawable) args.result);
- } else if (args.defaultResource != -1) {
- args.view.setVisibility(View.VISIBLE);
- args.view.setImageResource(args.defaultResource);
- }
- break;
- case EVENT_LOAD_DRAWABLE:
- if (args.result != null) {
- args.item.mBadge = (Drawable) args.result;
- if (args.callback != null) {
- args.callback.run();
- }
- }
- break;
- default:
- }
- }
-}
diff --git a/src/com/android/calendar/DayFragment.java b/src/com/android/calendar/DayFragment.java
index 72525959..8999141d 100644
--- a/src/com/android/calendar/DayFragment.java
+++ b/src/com/android/calendar/DayFragment.java
@@ -139,11 +139,6 @@ public class DayFragment extends Fragment implements CalendarController.EventHan
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
-
- long time = getSelectedTimeInMillis();
- if (time != -1) {
- outState.putLong(BUNDLE_KEY_RESTORE_TIME, time);
- }
}
@Override
diff --git a/src/com/android/calendar/DayOfMonthCursor.java b/src/com/android/calendar/DayOfMonthCursor.java
deleted file mode 100644
index f727669a..00000000
--- a/src/com/android/calendar/DayOfMonthCursor.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * 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.util.MonthDisplayHelper;
-
-/**
- * Helps control and display a month view of a calendar that has a current
- * selected day.
- * <ul>
- * <li>Keeps track of current month, day, year</li>
- * <li>Keeps track of current cursor position (row, column)</li>
- * <li>Provides methods to help display the calendar</li>
- * <li>Provides methods to move the cursor up / down / left / right.</li>
- * </ul>
- *
- * This should be used by anyone who presents a month view to users and wishes
- * to behave consistently with other widgets and apps; if we ever change our
- * mind about when to flip the month, we can change it here only.
- *
- * @hide
- */
-public class DayOfMonthCursor extends MonthDisplayHelper {
-
- private int mRow;
- private int mColumn;
-
- /**
- * @param year The initial year.
- * @param month The initial month.
- * @param dayOfMonth The initial dayOfMonth.
- * @param weekStartDay What dayOfMonth of the week the week should start,
- * in terms of {@link java.util.Calendar} constants such as
- * {@link java.util.Calendar#SUNDAY}.
- */
- public DayOfMonthCursor(int year, int month, int dayOfMonth, int weekStartDay) {
- super(year, month, weekStartDay);
- mRow = getRowOf(dayOfMonth);
- mColumn = getColumnOf(dayOfMonth);
- }
-
-
- public int getSelectedRow() {
- return mRow;
- }
-
- public int getSelectedColumn() {
- return mColumn;
- }
-
- public void setSelectedRowColumn(int row, int col) {
- mRow = row;
- mColumn = col;
- }
-
- public int getSelectedDayOfMonth() {
- return getDayAt(mRow, mColumn);
- }
-
- /**
- * @return 0 if the selection is in the current month, otherwise -1 or +1
- * depending on whether the selection is in the first or last row.
- */
- public int getSelectedMonthOffset() {
- if (isWithinCurrentMonth(mRow, mColumn)) {
- return 0;
- }
- if (mRow == 0) {
- return -1;
- }
- return 1;
- }
-
- public void setSelectedDayOfMonth(int dayOfMonth) {
- mRow = getRowOf(dayOfMonth);
- mColumn = getColumnOf(dayOfMonth);
- }
-
- public boolean isSelected(int row, int column) {
- return (mRow == row) && (mColumn == column);
- }
-
- /**
- * Move up one box, potentially flipping to the previous month.
- * @return Whether the month was flipped to the previous month
- * due to the move.
- */
- public boolean up() {
- if (isWithinCurrentMonth(mRow - 1, mColumn)) {
- // within current month, just move up
- mRow--;
- return false;
- }
- // flip back to previous month, same column, first position within month
- previousMonth();
- mRow = 5;
- while(!isWithinCurrentMonth(mRow, mColumn)) {
- mRow--;
- }
- return true;
- }
-
- /**
- * Move down one box, potentially flipping to the next month.
- * @return Whether the month was flipped to the next month
- * due to the move.
- */
- public boolean down() {
- if (isWithinCurrentMonth(mRow + 1, mColumn)) {
- // within current month, just move down
- mRow++;
- return false;
- }
- // flip to next month, same column, first position within month
- nextMonth();
- mRow = 0;
- while (!isWithinCurrentMonth(mRow, mColumn)) {
- mRow++;
- }
- return true;
- }
-
- /**
- * Move left one box, potentially flipping to the previous month.
- * @return Whether the month was flipped to the previous month
- * due to the move.
- */
- public boolean left() {
- if (mColumn == 0) {
- mRow--;
- mColumn = 6;
- } else {
- mColumn--;
- }
-
- if (isWithinCurrentMonth(mRow, mColumn)) {
- return false;
- }
-
- // need to flip to last day of previous month
- previousMonth();
- int lastDay = getNumberOfDaysInMonth();
- mRow = getRowOf(lastDay);
- mColumn = getColumnOf(lastDay);
- return true;
- }
-
- /**
- * Move right one box, potentially flipping to the next month.
- * @return Whether the month was flipped to the next month
- * due to the move.
- */
- public boolean right() {
- if (mColumn == 6) {
- mRow++;
- mColumn = 0;
- } else {
- mColumn++;
- }
-
- if (isWithinCurrentMonth(mRow, mColumn)) {
- return false;
- }
-
- // need to flip to first day of next month
- nextMonth();
- mRow = 0;
- mColumn = 0;
- while (!isWithinCurrentMonth(mRow, mColumn)) {
- mColumn++;
- }
- return true;
- }
-
-}
diff --git a/src/com/android/calendar/DayView.java b/src/com/android/calendar/DayView.java
index 68ae6a46..c9f3093d 100644
--- a/src/com/android/calendar/DayView.java
+++ b/src/com/android/calendar/DayView.java
@@ -112,7 +112,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
// duration to show the event clicked
private static final int CLICK_DISPLAY_DURATION = 50;
- private static final int MENU_AGENDA = 2;
private static final int MENU_DAY = 3;
private static final int MENU_EVENT_VIEW = 5;
private static final int MENU_EVENT_CREATE = 6;
@@ -181,8 +180,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
private int[] mEarliestStartHour; // indexed by the week day offset
private boolean[] mHasAllDayEvent; // indexed by the week day offset
private String mEventCountTemplate;
- private final CharSequence[] mLongPressItems;
- private String mLongPressTitle;
private Event mClickedEvent; // The event the user clicked on
private Event mSavedClickedEvent;
private static int mOnDownDelay;
@@ -570,11 +567,8 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
protected Drawable mAcceptedOrTentativeEventBoxDrawable;
private String mAmString;
private String mPmString;
- private final DeleteEventHelper mDeleteEventHelper;
private static int sCounter = 0;
- private final ContextMenuHandler mContextMenuHandler = new ContextMenuHandler();
-
ScaleGestureDetector mScaleGestureDetector;
/**
@@ -646,7 +640,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
private AccessibilityManager mAccessibilityMgr = null;
private boolean mIsAccessibilityEnabled = false;
private boolean mTouchExplorationEnabled = false;
- private final String mCreateNewEventString;
private final String mNewEventHintString;
public DayView(Context context, CalendarController controller,
@@ -656,7 +649,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
initAccessibilityVariables();
mResources = context.getResources();
- mCreateNewEventString = mResources.getString(R.string.event_create);
mNewEventHintString = mResources.getString(R.string.day_view_new_event_hint);
mNumDays = numDays;
@@ -750,11 +742,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
mEventGeometry.setMinEventHeight(MIN_EVENT_HEIGHT);
mEventGeometry.setHourGap(HOUR_GAP);
mEventGeometry.setCellMargin(DAY_GAP);
- mLongPressItems = new CharSequence[] {
- mResources.getString(R.string.new_event_dialog_option)
- };
- mLongPressTitle = mResources.getString(R.string.new_event_dialog_label);
- mDeleteEventHelper = new DeleteEventHelper(context, null, false /* don't exit when done */);
mLastPopupEventID = INVALID_EVENT_ID;
mController = controller;
mViewSwitcher = viewSwitcher;
@@ -1407,281 +1394,29 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
// With track ball, if we selected a free slot, then create an event.
// If we selected a specific event, switch to EventInfo view.
if (trackBallSelection) {
- if (selectedEvent == null) {
- // Switch to the EditEvent view
- long startMillis = getSelectedTimeInMillis();
- long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS;
- long extraLong = 0;
- if (mSelectionAllday) {
- extraLong = CalendarController.EXTRA_CREATE_ALL_DAY;
- }
- mController.sendEventRelatedEventWithExtra(this, EventType.CREATE_EVENT, -1,
- startMillis, endMillis, -1, -1, extraLong, -1);
- } else {
+ if (selectedEvent != null) {
if (mIsAccessibilityEnabled) {
mAccessibilityMgr.interrupt();
}
- // Switch to the EventInfo view
- mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, selectedEvent.id,
- selectedEvent.startMillis, selectedEvent.endMillis, 0, 0,
- getSelectedTimeInMillis());
- }
- } else {
- // This was a touch selection. If the touch selected a single
- // unambiguous event, then view that event. Otherwise go to
- // Day/Agenda view.
- if (mSelectedEvents.size() == 1) {
- if (mIsAccessibilityEnabled) {
- mAccessibilityMgr.interrupt();
- }
- mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, selectedEvent.id,
- selectedEvent.startMillis, selectedEvent.endMillis, 0, 0,
- getSelectedTimeInMillis());
}
}
- } else {
- // This is the Day view.
- // If we selected a free slot, then create an event.
- // If we selected an event, then go to the EventInfo view.
- if (selectedEvent == null) {
- // Switch to the EditEvent view
- long startMillis = getSelectedTimeInMillis();
- long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS;
- long extraLong = 0;
- if (mSelectionAllday) {
- extraLong = CalendarController.EXTRA_CREATE_ALL_DAY;
- }
- mController.sendEventRelatedEventWithExtra(this, EventType.CREATE_EVENT, -1,
- startMillis, endMillis, -1, -1, extraLong, -1);
- } else {
- if (mIsAccessibilityEnabled) {
- mAccessibilityMgr.interrupt();
- }
- mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT, selectedEvent.id,
- selectedEvent.startMillis, selectedEvent.endMillis, 0, 0,
- getSelectedTimeInMillis());
- }
}
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
mScrolling = false;
- long duration = event.getEventTime() - event.getDownTime();
-
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_CENTER:
- if (mSelectionMode == SELECTION_HIDDEN) {
- // Don't do anything unless the selection is visible.
- break;
- }
-
- if (mSelectionMode == SELECTION_PRESSED) {
- // This was the first press when there was nothing selected.
- // Change the selection from the "pressed" state to the
- // the "selected" state. We treat short-press and
- // long-press the same here because nothing was selected.
- mSelectionMode = SELECTION_SELECTED;
- invalidate();
- break;
- }
-
- // Check the duration to determine if this was a short press
- if (duration < ViewConfiguration.getLongPressTimeout()) {
- switchViews(true /* trackball */);
- } else {
- mSelectionMode = SELECTION_LONGPRESS;
- invalidate();
- performLongClick();
- }
- break;
-// case KeyEvent.KEYCODE_BACK:
-// if (event.isTracking() && !event.isCanceled()) {
-// mPopup.dismiss();
-// mContext.finish();
-// return true;
-// }
-// break;
- }
return super.onKeyUp(keyCode, event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (mSelectionMode == SELECTION_HIDDEN) {
- if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
- || keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_UP
- || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
- // Display the selection box but don't move or select it
- // on this key press.
- mSelectionMode = SELECTION_SELECTED;
- invalidate();
- return true;
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
- // Display the selection box but don't select it
- // on this key press.
- mSelectionMode = SELECTION_PRESSED;
- invalidate();
- return true;
- }
- }
-
- mSelectionMode = SELECTION_SELECTED;
- mScrolling = false;
- boolean redraw;
- int selectionDay = mSelectionDay;
-
- switch (keyCode) {
- case KeyEvent.KEYCODE_DEL:
- // Delete the selected event, if any
- Event selectedEvent = mSelectedEvent;
- if (selectedEvent == null) {
- return false;
- }
- mPopup.dismiss();
- mLastPopupEventID = INVALID_EVENT_ID;
-
- long begin = selectedEvent.startMillis;
- long end = selectedEvent.endMillis;
- long id = selectedEvent.id;
- mDeleteEventHelper.delete(begin, end, id, -1);
- return true;
- case KeyEvent.KEYCODE_ENTER:
- switchViews(true /* trackball or keyboard */);
- return true;
- case KeyEvent.KEYCODE_BACK:
- if (event.getRepeatCount() == 0) {
- event.startTracking();
- return true;
- }
- return super.onKeyDown(keyCode, event);
- case KeyEvent.KEYCODE_DPAD_LEFT:
- if (mSelectedEvent != null) {
- setSelectedEvent(mSelectedEvent.nextLeft);
- }
- if (mSelectedEvent == null) {
- mLastPopupEventID = INVALID_EVENT_ID;
- selectionDay -= 1;
- }
- redraw = true;
- break;
-
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (mSelectedEvent != null) {
- setSelectedEvent(mSelectedEvent.nextRight);
- }
- if (mSelectedEvent == null) {
- mLastPopupEventID = INVALID_EVENT_ID;
- selectionDay += 1;
- }
- redraw = true;
- break;
-
- case KeyEvent.KEYCODE_DPAD_UP:
- if (mSelectedEvent != null) {
- setSelectedEvent(mSelectedEvent.nextUp);
- }
- if (mSelectedEvent == null) {
- mLastPopupEventID = INVALID_EVENT_ID;
- if (!mSelectionAllday) {
- setSelectedHour(mSelectionHour - 1);
- adjustHourSelection();
- mSelectedEvents.clear();
- mComputeSelectedEvents = true;
- }
- }
- redraw = true;
- break;
-
- case KeyEvent.KEYCODE_DPAD_DOWN:
- if (mSelectedEvent != null) {
- setSelectedEvent(mSelectedEvent.nextDown);
- }
- if (mSelectedEvent == null) {
- mLastPopupEventID = INVALID_EVENT_ID;
- if (mSelectionAllday) {
- mSelectionAllday = false;
- } else {
- setSelectedHour(mSelectionHour + 1);
- adjustHourSelection();
- mSelectedEvents.clear();
- mComputeSelectedEvents = true;
- }
- }
- redraw = true;
- break;
-
- default:
- return super.onKeyDown(keyCode, event);
- }
-
- if ((selectionDay < mFirstJulianDay) || (selectionDay > mLastJulianDay)) {
- DayView view = (DayView) mViewSwitcher.getNextView();
- Time date = view.mBaseDate;
- date.set(mBaseDate);
- if (selectionDay < mFirstJulianDay) {
- date.monthDay -= mNumDays;
- } else {
- date.monthDay += mNumDays;
- }
- date.normalize(true /* ignore isDst */);
- view.setSelectedDay(selectionDay);
-
- initView(view);
-
- Time end = new Time(date);
- end.monthDay += mNumDays - 1;
- mController.sendEvent(this, EventType.GO_TO, date, end, -1, ViewType.CURRENT);
- return true;
- }
- if (mSelectionDay != selectionDay) {
- Time date = new Time(mBaseDate);
- date.setJulianDay(selectionDay);
- date.hour = mSelectionHour;
- mController.sendEvent(this, EventType.GO_TO, date, date, -1, ViewType.CURRENT);
- }
- setSelectedDay(selectionDay);
- mSelectedEvents.clear();
- mComputeSelectedEvents = true;
- mUpdateToast = true;
-
- if (redraw) {
- invalidate();
- return true;
- }
-
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onHoverEvent(MotionEvent event) {
- if (DEBUG) {
- int action = event.getAction();
- switch (action) {
- case MotionEvent.ACTION_HOVER_ENTER:
- Log.e(TAG, "ACTION_HOVER_ENTER");
- break;
- case MotionEvent.ACTION_HOVER_MOVE:
- Log.e(TAG, "ACTION_HOVER_MOVE");
- break;
- case MotionEvent.ACTION_HOVER_EXIT:
- Log.e(TAG, "ACTION_HOVER_EXIT");
- break;
- default:
- Log.e(TAG, "Unknown hover event action. " + event);
- }
- }
-
- // Mouse also generates hover events
- // Send accessibility events if accessibility and exploration are on.
- if (!mTouchExplorationEnabled) {
- return super.onHoverEvent(event);
- }
- if (event.getAction() != MotionEvent.ACTION_HOVER_EXIT) {
- setSelectionFromPosition((int) event.getX(), (int) event.getY(), true);
- invalidate();
- }
return true;
}
@@ -1744,8 +1479,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
}
appendEventAccessibilityString(b, mSelectedEventForAccessibility);
}
- } else {
- b.append(mCreateNewEventString);
}
}
@@ -2218,7 +1951,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
// Draw the fixed areas (that don't scroll) directly to the canvas.
drawAfterScroll(canvas);
if (mComputeSelectedEvents && mUpdateToast) {
- updateEventDetails();
mUpdateToast = false;
}
mComputeSelectedEvents = false;
@@ -2338,17 +2070,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
canvas.drawRect(r, p);
}
}
-
- if (mSelectionAllday && mSelectionMode != SELECTION_HIDDEN) {
- // Draw the selection highlight on the selected all-day area
- mRect.top = DAY_HEADER_HEIGHT + 1;
- mRect.bottom = mRect.top + mAlldayHeight + ALLDAY_TOP_MARGIN - 2;
- int daynum = mSelectionDay - mFirstJulianDay;
- mRect.left = computeDayLeftPosition(daynum) + 1;
- mRect.right = computeDayLeftPosition(daynum + 1);
- p.setColor(mCalendarGridAreaSelected);
- canvas.drawRect(mRect, p);
- }
}
private void drawDayHeaderLoop(Rect r, Canvas canvas, Paint p) {
@@ -2480,52 +2201,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
}
p.setAntiAlias(true);
p.setAlpha(alpha);
-
- drawSelectedRect(r, canvas, p);
- }
-
- private void drawSelectedRect(Rect r, Canvas canvas, Paint p) {
- // Draw a highlight on the selected hour (if needed)
- if (mSelectionMode != SELECTION_HIDDEN && !mSelectionAllday) {
- int daynum = mSelectionDay - mFirstJulianDay;
- r.top = mSelectionHour * (mCellHeight + HOUR_GAP);
- r.bottom = r.top + mCellHeight + HOUR_GAP;
- r.left = computeDayLeftPosition(daynum) + 1;
- r.right = computeDayLeftPosition(daynum + 1) + 1;
-
- saveSelectionPosition(r.left, r.top, r.right, r.bottom);
-
- // Draw the highlight on the grid
- p.setColor(mCalendarGridAreaSelected);
- r.top += HOUR_GAP;
- r.right -= DAY_GAP;
- p.setAntiAlias(false);
- canvas.drawRect(r, p);
-
- // Draw a "new event hint" on top of the highlight
- // For the week view, show a "+", for day view, show "+ New event"
- p.setColor(mNewEventHintColor);
- if (mNumDays > 1) {
- p.setStrokeWidth(NEW_EVENT_WIDTH);
- int width = r.right - r.left;
- int midX = r.left + width / 2;
- int midY = r.top + mCellHeight / 2;
- int length = Math.min(mCellHeight, width) - NEW_EVENT_MARGIN * 2;
- length = Math.min(length, NEW_EVENT_MAX_LENGTH);
- int verticalPadding = (mCellHeight - length) / 2;
- int horizontalPadding = (width - length) / 2;
- canvas.drawLine(r.left + horizontalPadding, midY, r.right - horizontalPadding,
- midY, p);
- canvas.drawLine(midX, r.top + verticalPadding, midX, r.bottom - verticalPadding, p);
- } else {
- p.setStyle(Paint.Style.FILL);
- p.setTextSize(NEW_EVENT_HINT_FONT_SIZE);
- p.setTextAlign(Paint.Align.LEFT);
- p.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
- canvas.drawText(mNewEventHintString, r.left + EVENT_TEXT_LEFT_MARGIN,
- r.top + Math.abs(p.getFontMetrics().ascent) + EVENT_TEXT_TOP_MARGIN , p);
- }
- }
}
private void drawHours(Rect r, Canvas canvas, Paint p) {
@@ -2757,16 +2432,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
mPrevBox.bottom = (int) bottom;
}
- private Rect getCurrentSelectionPosition() {
- Rect box = new Rect();
- box.top = mSelectionHour * (mCellHeight + HOUR_GAP);
- box.bottom = box.top + mCellHeight + HOUR_GAP;
- int daynum = mSelectionDay - mFirstJulianDay;
- box.left = computeDayLeftPosition(daynum) + 1;
- box.right = computeDayLeftPosition(daynum + 1);
- return box;
- }
-
private void setupTextRect(Rect r) {
if (r.bottom <= r.top || r.right <= r.left) {
r.bottom = r.top;
@@ -3139,298 +2804,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
- DAY_HEADER_HEIGHT - mAlldayHeight, false);
}
eventTextPaint.setAlpha(alpha);
-
- if (date == mSelectionDay && !mSelectionAllday && isFocused()
- && mSelectionMode != SELECTION_HIDDEN) {
- computeNeighbors();
- }
- }
-
- // Computes the "nearest" neighbor event in four directions (left, right,
- // up, down) for each of the events in the mSelectedEvents array.
- private void computeNeighbors() {
- int len = mSelectedEvents.size();
- if (len == 0 || mSelectedEvent != null) {
- return;
- }
-
- // First, clear all the links
- for (int ii = 0; ii < len; ii++) {
- Event ev = mSelectedEvents.get(ii);
- ev.nextUp = null;
- ev.nextDown = null;
- ev.nextLeft = null;
- ev.nextRight = null;
- }
-
- Event startEvent = mSelectedEvents.get(0);
- int startEventDistance1 = 100000; // any large number
- int startEventDistance2 = 100000; // any large number
- int prevLocation = FROM_NONE;
- int prevTop;
- int prevBottom;
- int prevLeft;
- int prevRight;
- int prevCenter = 0;
- Rect box = getCurrentSelectionPosition();
- if (mPrevSelectedEvent != null) {
- prevTop = (int) mPrevSelectedEvent.top;
- prevBottom = (int) mPrevSelectedEvent.bottom;
- prevLeft = (int) mPrevSelectedEvent.left;
- prevRight = (int) mPrevSelectedEvent.right;
- // Check if the previously selected event intersects the previous
- // selection box. (The previously selected event may be from a
- // much older selection box.)
- if (prevTop >= mPrevBox.bottom || prevBottom <= mPrevBox.top
- || prevRight <= mPrevBox.left || prevLeft >= mPrevBox.right) {
- mPrevSelectedEvent = null;
- prevTop = mPrevBox.top;
- prevBottom = mPrevBox.bottom;
- prevLeft = mPrevBox.left;
- prevRight = mPrevBox.right;
- } else {
- // Clip the top and bottom to the previous selection box.
- if (prevTop < mPrevBox.top) {
- prevTop = mPrevBox.top;
- }
- if (prevBottom > mPrevBox.bottom) {
- prevBottom = mPrevBox.bottom;
- }
- }
- } else {
- // Just use the previously drawn selection box
- prevTop = mPrevBox.top;
- prevBottom = mPrevBox.bottom;
- prevLeft = mPrevBox.left;
- prevRight = mPrevBox.right;
- }
-
- // Figure out where we came from and compute the center of that area.
- if (prevLeft >= box.right) {
- // The previously selected event was to the right of us.
- prevLocation = FROM_RIGHT;
- prevCenter = (prevTop + prevBottom) / 2;
- } else if (prevRight <= box.left) {
- // The previously selected event was to the left of us.
- prevLocation = FROM_LEFT;
- prevCenter = (prevTop + prevBottom) / 2;
- } else if (prevBottom <= box.top) {
- // The previously selected event was above us.
- prevLocation = FROM_ABOVE;
- prevCenter = (prevLeft + prevRight) / 2;
- } else if (prevTop >= box.bottom) {
- // The previously selected event was below us.
- prevLocation = FROM_BELOW;
- prevCenter = (prevLeft + prevRight) / 2;
- }
-
- // For each event in the selected event list "mSelectedEvents", search
- // all the other events in that list for the nearest neighbor in 4
- // directions.
- for (int ii = 0; ii < len; ii++) {
- Event ev = mSelectedEvents.get(ii);
-
- int startTime = ev.startTime;
- int endTime = ev.endTime;
- int left = (int) ev.left;
- int right = (int) ev.right;
- int top = (int) ev.top;
- if (top < box.top) {
- top = box.top;
- }
- int bottom = (int) ev.bottom;
- if (bottom > box.bottom) {
- bottom = box.bottom;
- }
-// if (false) {
-// int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL
-// | DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
-// if (DateFormat.is24HourFormat(mContext)) {
-// flags |= DateUtils.FORMAT_24HOUR;
-// }
-// String timeRange = DateUtils.formatDateRange(mContext, ev.startMillis,
-// ev.endMillis, flags);
-// Log.i("Cal", "left: " + left + " right: " + right + " top: " + top + " bottom: "
-// + bottom + " ev: " + timeRange + " " + ev.title);
-// }
- int upDistanceMin = 10000; // any large number
- int downDistanceMin = 10000; // any large number
- int leftDistanceMin = 10000; // any large number
- int rightDistanceMin = 10000; // any large number
- Event upEvent = null;
- Event downEvent = null;
- Event leftEvent = null;
- Event rightEvent = null;
-
- // Pick the starting event closest to the previously selected event,
- // if any. distance1 takes precedence over distance2.
- int distance1 = 0;
- int distance2 = 0;
- if (prevLocation == FROM_ABOVE) {
- if (left >= prevCenter) {
- distance1 = left - prevCenter;
- } else if (right <= prevCenter) {
- distance1 = prevCenter - right;
- }
- distance2 = top - prevBottom;
- } else if (prevLocation == FROM_BELOW) {
- if (left >= prevCenter) {
- distance1 = left - prevCenter;
- } else if (right <= prevCenter) {
- distance1 = prevCenter - right;
- }
- distance2 = prevTop - bottom;
- } else if (prevLocation == FROM_LEFT) {
- if (bottom <= prevCenter) {
- distance1 = prevCenter - bottom;
- } else if (top >= prevCenter) {
- distance1 = top - prevCenter;
- }
- distance2 = left - prevRight;
- } else if (prevLocation == FROM_RIGHT) {
- if (bottom <= prevCenter) {
- distance1 = prevCenter - bottom;
- } else if (top >= prevCenter) {
- distance1 = top - prevCenter;
- }
- distance2 = prevLeft - right;
- }
- if (distance1 < startEventDistance1
- || (distance1 == startEventDistance1 && distance2 < startEventDistance2)) {
- startEvent = ev;
- startEventDistance1 = distance1;
- startEventDistance2 = distance2;
- }
-
- // For each neighbor, figure out if it is above or below or left
- // or right of me and compute the distance.
- for (int jj = 0; jj < len; jj++) {
- if (jj == ii) {
- continue;
- }
- Event neighbor = mSelectedEvents.get(jj);
- int neighborLeft = (int) neighbor.left;
- int neighborRight = (int) neighbor.right;
- if (neighbor.endTime <= startTime) {
- // This neighbor is entirely above me.
- // If we overlap the same column, then compute the distance.
- if (neighborLeft < right && neighborRight > left) {
- int distance = startTime - neighbor.endTime;
- if (distance < upDistanceMin) {
- upDistanceMin = distance;
- upEvent = neighbor;
- } else if (distance == upDistanceMin) {
- int center = (left + right) / 2;
- int currentDistance = 0;
- int currentLeft = (int) upEvent.left;
- int currentRight = (int) upEvent.right;
- if (currentRight <= center) {
- currentDistance = center - currentRight;
- } else if (currentLeft >= center) {
- currentDistance = currentLeft - center;
- }
-
- int neighborDistance = 0;
- if (neighborRight <= center) {
- neighborDistance = center - neighborRight;
- } else if (neighborLeft >= center) {
- neighborDistance = neighborLeft - center;
- }
- if (neighborDistance < currentDistance) {
- upDistanceMin = distance;
- upEvent = neighbor;
- }
- }
- }
- } else if (neighbor.startTime >= endTime) {
- // This neighbor is entirely below me.
- // If we overlap the same column, then compute the distance.
- if (neighborLeft < right && neighborRight > left) {
- int distance = neighbor.startTime - endTime;
- if (distance < downDistanceMin) {
- downDistanceMin = distance;
- downEvent = neighbor;
- } else if (distance == downDistanceMin) {
- int center = (left + right) / 2;
- int currentDistance = 0;
- int currentLeft = (int) downEvent.left;
- int currentRight = (int) downEvent.right;
- if (currentRight <= center) {
- currentDistance = center - currentRight;
- } else if (currentLeft >= center) {
- currentDistance = currentLeft - center;
- }
-
- int neighborDistance = 0;
- if (neighborRight <= center) {
- neighborDistance = center - neighborRight;
- } else if (neighborLeft >= center) {
- neighborDistance = neighborLeft - center;
- }
- if (neighborDistance < currentDistance) {
- downDistanceMin = distance;
- downEvent = neighbor;
- }
- }
- }
- }
-
- if (neighborLeft >= right) {
- // This neighbor is entirely to the right of me.
- // Take the closest neighbor in the y direction.
- int center = (top + bottom) / 2;
- int distance = 0;
- int neighborBottom = (int) neighbor.bottom;
- int neighborTop = (int) neighbor.top;
- if (neighborBottom <= center) {
- distance = center - neighborBottom;
- } else if (neighborTop >= center) {
- distance = neighborTop - center;
- }
- if (distance < rightDistanceMin) {
- rightDistanceMin = distance;
- rightEvent = neighbor;
- } else if (distance == rightDistanceMin) {
- // Pick the closest in the x direction
- int neighborDistance = neighborLeft - right;
- int currentDistance = (int) rightEvent.left - right;
- if (neighborDistance < currentDistance) {
- rightDistanceMin = distance;
- rightEvent = neighbor;
- }
- }
- } else if (neighborRight <= left) {
- // This neighbor is entirely to the left of me.
- // Take the closest neighbor in the y direction.
- int center = (top + bottom) / 2;
- int distance = 0;
- int neighborBottom = (int) neighbor.bottom;
- int neighborTop = (int) neighbor.top;
- if (neighborBottom <= center) {
- distance = center - neighborBottom;
- } else if (neighborTop >= center) {
- distance = neighborTop - center;
- }
- if (distance < leftDistanceMin) {
- leftDistanceMin = distance;
- leftEvent = neighbor;
- } else if (distance == leftDistanceMin) {
- // Pick the closest in the x direction
- int neighborDistance = left - neighborRight;
- int currentDistance = left - (int) leftEvent.right;
- if (neighborDistance < currentDistance) {
- leftDistanceMin = distance;
- leftEvent = neighbor;
- }
- }
- }
- }
- ev.nextUp = upEvent;
- ev.nextDown = downEvent;
- ev.nextLeft = leftEvent;
- ev.nextRight = rightEvent;
- }
- setSelectedEvent(startEvent);
}
private Rect drawEventRect(Event event, Canvas canvas, Paint p, Paint eventTextPaint,
@@ -3488,18 +2861,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
if (mSelectedEvent == event && mClickedEvent != null) {
boolean paintIt = false;
color = 0;
- if (mSelectionMode == SELECTION_PRESSED) {
- // Also, remember the last selected event that we drew
- mPrevSelectedEvent = event;
- color = mPressedColor;
- paintIt = true;
- } else if (mSelectionMode == SELECTION_SELECTED) {
- // Also, remember the last selected event that we drew
- mPrevSelectedEvent = event;
- color = mPressedColor;
- paintIt = true;
- }
-
if (paintIt) {
p.setColor(color);
canvas.drawRect(r, p);
@@ -3507,22 +2868,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
p.setAntiAlias(true);
}
- // Draw cal color square border
- // r.top = (int) event.top + CALENDAR_COLOR_SQUARE_V_OFFSET;
- // r.left = (int) event.left + CALENDAR_COLOR_SQUARE_H_OFFSET;
- // r.bottom = r.top + CALENDAR_COLOR_SQUARE_SIZE + 1;
- // r.right = r.left + CALENDAR_COLOR_SQUARE_SIZE + 1;
- // p.setColor(0xFFFFFFFF);
- // canvas.drawRect(r, p);
-
- // Draw cal color
- // r.top++;
- // r.left++;
- // r.bottom--;
- // r.right--;
- // p.setColor(event.color);
- // canvas.drawRect(r, p);
-
// Setup rect for drawEventText which follows
r.top = (int) event.top + EVENT_RECT_TOP_MARGIN;
r.bottom = (int) event.bottom - EVENT_RECT_BOTTOM_MARGIN;
@@ -3600,84 +2945,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
canvas.restore();
}
- // This is to replace p.setStyle(Style.STROKE); canvas.drawRect() since it
- // doesn't work well with hardware acceleration
-// private void drawEmptyRect(Canvas canvas, Rect r, int color) {
-// int linesIndex = 0;
-// mLines[linesIndex++] = r.left;
-// mLines[linesIndex++] = r.top;
-// mLines[linesIndex++] = r.right;
-// mLines[linesIndex++] = r.top;
-//
-// mLines[linesIndex++] = r.left;
-// mLines[linesIndex++] = r.bottom;
-// mLines[linesIndex++] = r.right;
-// mLines[linesIndex++] = r.bottom;
-//
-// mLines[linesIndex++] = r.left;
-// mLines[linesIndex++] = r.top;
-// mLines[linesIndex++] = r.left;
-// mLines[linesIndex++] = r.bottom;
-//
-// mLines[linesIndex++] = r.right;
-// mLines[linesIndex++] = r.top;
-// mLines[linesIndex++] = r.right;
-// mLines[linesIndex++] = r.bottom;
-// mPaint.setColor(color);
-// canvas.drawLines(mLines, 0, linesIndex, mPaint);
-// }
-
- private void updateEventDetails() {
- if (mSelectedEvent == null || mSelectionMode == SELECTION_HIDDEN
- || mSelectionMode == SELECTION_LONGPRESS) {
- mPopup.dismiss();
- return;
- }
- if (mLastPopupEventID == mSelectedEvent.id) {
- return;
- }
-
- mLastPopupEventID = mSelectedEvent.id;
-
- // Remove any outstanding callbacks to dismiss the popup.
- mHandler.removeCallbacks(mDismissPopup);
-
- Event event = mSelectedEvent;
- TextView titleView = (TextView) mPopupView.findViewById(R.id.event_title);
- titleView.setText(event.title);
-
- ImageView imageView = (ImageView) mPopupView.findViewById(R.id.reminder_icon);
- imageView.setVisibility(event.hasAlarm ? View.VISIBLE : View.GONE);
-
- imageView = (ImageView) mPopupView.findViewById(R.id.repeat_icon);
- imageView.setVisibility(event.isRepeating ? View.VISIBLE : View.GONE);
-
- int flags;
- if (event.allDay) {
- flags = DateUtils.FORMAT_UTC | DateUtils.FORMAT_SHOW_DATE
- | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_ALL;
- } else {
- flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE
- | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_ALL
- | DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
- }
- if (DateFormat.is24HourFormat(mContext)) {
- flags |= DateUtils.FORMAT_24HOUR;
- }
- String timeRange = Utils.formatDateRange(mContext, event.startMillis, event.endMillis,
- flags);
- TextView timeView = (TextView) mPopupView.findViewById(R.id.time);
- timeView.setText(timeRange);
-
- TextView whereView = (TextView) mPopupView.findViewById(R.id.where);
- final boolean empty = TextUtils.isEmpty(event.location);
- whereView.setVisibility(empty ? View.GONE : View.VISIBLE);
- if (!empty) whereView.setText(event.location);
-
- mPopup.showAtLocation(this, Gravity.BOTTOM | Gravity.LEFT, mHoursWidth, 5);
- mHandler.postDelayed(mDismissPopup, POPUP_DISMISS_DELAY);
- }
-
// The following routines are called from the parent activity when certain
// touch events occur.
private void doDown(MotionEvent ev) {
@@ -3891,18 +3158,7 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
boolean pressedSelected = (hasSelection || mTouchExplorationEnabled)
&& selectedDay == mSelectionDay && selectedHour == mSelectionHour;
- if (pressedSelected && mSavedClickedEvent == null) {
- // If the tap is on an already selected hour slot, then create a new
- // event
- long extraLong = 0;
- if (mSelectionAllday) {
- extraLong = CalendarController.EXTRA_CREATE_ALL_DAY;
- }
- mSelectionMode = SELECTION_SELECTED;
- mController.sendEventRelatedEventWithExtra(this, EventType.CREATE_EVENT, -1,
- getSelectedTimeInMillis(), 0, (int) ev.getRawX(), (int) ev.getRawY(),
- extraLong, -1);
- } else if (mSelectedEvent != null) {
+ if (mSelectedEvent != null) {
// If the tap is on an event, launch the "View event" view
if (mIsAccessibilityEnabled) {
mAccessibilityMgr.interrupt();
@@ -3925,19 +3181,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
} else {
this.post(mClearClick);
}
- } else {
- // Select time
- Time startTime = new Time(mBaseDate);
- startTime.setJulianDay(mSelectionDay);
- startTime.hour = mSelectionHour;
- startTime.normalize(true /* ignore isDst */);
-
- Time endTime = new Time(startTime);
- endTime.hour++;
-
- mSelectionMode = SELECTION_SELECTED;
- mController.sendEvent(this, EventType.GO_TO, startTime, endTime, -1, ViewType.CURRENT,
- CalendarController.EXTRA_GOTO_TIME, null, null);
}
invalidate();
}
@@ -3962,7 +3205,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
return;
}
- mSelectionMode = SELECTION_LONGPRESS;
invalidate();
performLongClick();
}
@@ -4341,7 +3583,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
// we never get onKeyUp() for the long-press. So check for it here
// and change the selection to the long-press state.
if (mSelectionMode != SELECTION_LONGPRESS) {
- mSelectionMode = SELECTION_LONGPRESS;
invalidate();
}
@@ -4352,191 +3593,9 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
final String title = Utils.formatDateRange(mContext, startMillis, startMillis, flags);
menu.setHeaderTitle(title);
- int numSelectedEvents = mSelectedEvents.size();
- if (mNumDays == 1) {
- // Day view.
-
- // If there is a selected event, then allow it to be viewed and
- // edited.
- if (numSelectedEvents >= 1) {
- item = menu.add(0, MENU_EVENT_VIEW, 0, R.string.event_view);
- item.setOnMenuItemClickListener(mContextMenuHandler);
- item.setIcon(android.R.drawable.ic_menu_info_details);
-
- int accessLevel = getEventAccessLevel(mContext, mSelectedEvent);
- if (accessLevel == ACCESS_LEVEL_EDIT) {
- item = menu.add(0, MENU_EVENT_EDIT, 0, R.string.event_edit);
- item.setOnMenuItemClickListener(mContextMenuHandler);
- item.setIcon(android.R.drawable.ic_menu_edit);
- item.setAlphabeticShortcut('e');
- }
-
- if (accessLevel >= ACCESS_LEVEL_DELETE) {
- item = menu.add(0, MENU_EVENT_DELETE, 0, R.string.event_delete);
- item.setOnMenuItemClickListener(mContextMenuHandler);
- item.setIcon(android.R.drawable.ic_menu_delete);
- }
-
- item = menu.add(0, MENU_EVENT_CREATE, 0, R.string.event_create);
- item.setOnMenuItemClickListener(mContextMenuHandler);
- item.setIcon(android.R.drawable.ic_menu_add);
- item.setAlphabeticShortcut('n');
- } else {
- // Otherwise, if the user long-pressed on a blank hour, allow
- // them to create an event. They can also do this by tapping.
- item = menu.add(0, MENU_EVENT_CREATE, 0, R.string.event_create);
- item.setOnMenuItemClickListener(mContextMenuHandler);
- item.setIcon(android.R.drawable.ic_menu_add);
- item.setAlphabeticShortcut('n');
- }
- } else {
- // Week view.
-
- // If there is a selected event, then allow it to be viewed and
- // edited.
- if (numSelectedEvents >= 1) {
- item = menu.add(0, MENU_EVENT_VIEW, 0, R.string.event_view);
- item.setOnMenuItemClickListener(mContextMenuHandler);
- item.setIcon(android.R.drawable.ic_menu_info_details);
-
- int accessLevel = getEventAccessLevel(mContext, mSelectedEvent);
- if (accessLevel == ACCESS_LEVEL_EDIT) {
- item = menu.add(0, MENU_EVENT_EDIT, 0, R.string.event_edit);
- item.setOnMenuItemClickListener(mContextMenuHandler);
- item.setIcon(android.R.drawable.ic_menu_edit);
- item.setAlphabeticShortcut('e');
- }
-
- if (accessLevel >= ACCESS_LEVEL_DELETE) {
- item = menu.add(0, MENU_EVENT_DELETE, 0, R.string.event_delete);
- item.setOnMenuItemClickListener(mContextMenuHandler);
- item.setIcon(android.R.drawable.ic_menu_delete);
- }
- }
-
- item = menu.add(0, MENU_EVENT_CREATE, 0, R.string.event_create);
- item.setOnMenuItemClickListener(mContextMenuHandler);
- item.setIcon(android.R.drawable.ic_menu_add);
- item.setAlphabeticShortcut('n');
-
- item = menu.add(0, MENU_DAY, 0, R.string.show_day_view);
- item.setOnMenuItemClickListener(mContextMenuHandler);
- item.setIcon(android.R.drawable.ic_menu_day);
- item.setAlphabeticShortcut('d');
- }
-
mPopup.dismiss();
}
- private class ContextMenuHandler implements MenuItem.OnMenuItemClickListener {
-
- public boolean onMenuItemClick(MenuItem item) {
- switch (item.getItemId()) {
- case MENU_EVENT_VIEW: {
- if (mSelectedEvent != null) {
- mController.sendEventRelatedEvent(this, EventType.VIEW_EVENT_DETAILS,
- mSelectedEvent.id, mSelectedEvent.startMillis,
- mSelectedEvent.endMillis, 0, 0, -1);
- }
- break;
- }
- case MENU_EVENT_EDIT: {
- if (mSelectedEvent != null) {
- mController.sendEventRelatedEvent(this, EventType.EDIT_EVENT,
- mSelectedEvent.id, mSelectedEvent.startMillis,
- mSelectedEvent.endMillis, 0, 0, -1);
- }
- break;
- }
- case MENU_DAY: {
- mController.sendEvent(this, EventType.GO_TO, getSelectedTime(), null, -1,
- ViewType.DAY);
- break;
- }
- case MENU_AGENDA: {
- mController.sendEvent(this, EventType.GO_TO, getSelectedTime(), null, -1,
- ViewType.AGENDA);
- break;
- }
- case MENU_EVENT_CREATE: {
- long startMillis = getSelectedTimeInMillis();
- long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS;
- mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1,
- startMillis, endMillis, 0, 0, -1);
- break;
- }
- case MENU_EVENT_DELETE: {
- if (mSelectedEvent != null) {
- Event selectedEvent = mSelectedEvent;
- long begin = selectedEvent.startMillis;
- long end = selectedEvent.endMillis;
- long id = selectedEvent.id;
- mController.sendEventRelatedEvent(this, EventType.DELETE_EVENT, id, begin,
- end, 0, 0, -1);
- }
- break;
- }
- default: {
- return false;
- }
- }
- return true;
- }
- }
-
- private static int getEventAccessLevel(Context context, Event e) {
- ContentResolver cr = context.getContentResolver();
-
- int accessLevel = Calendars.CAL_ACCESS_NONE;
-
- // Get the calendar id for this event
- Cursor cursor = cr.query(ContentUris.withAppendedId(Events.CONTENT_URI, e.id),
- new String[] { Events.CALENDAR_ID },
- null /* selection */,
- null /* selectionArgs */,
- null /* sort */);
-
- if (cursor == null) {
- return ACCESS_LEVEL_NONE;
- }
-
- if (cursor.getCount() == 0) {
- cursor.close();
- return ACCESS_LEVEL_NONE;
- }
-
- cursor.moveToFirst();
- long calId = cursor.getLong(0);
- cursor.close();
-
- Uri uri = Calendars.CONTENT_URI;
- String where = String.format(CALENDARS_WHERE, calId);
- cursor = cr.query(uri, CALENDARS_PROJECTION, where, null, null);
-
- String calendarOwnerAccount = null;
- if (cursor != null) {
- cursor.moveToFirst();
- accessLevel = cursor.getInt(CALENDARS_INDEX_ACCESS_LEVEL);
- calendarOwnerAccount = cursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
- cursor.close();
- }
-
- if (accessLevel < Calendars.CAL_ACCESS_CONTRIBUTOR) {
- return ACCESS_LEVEL_NONE;
- }
-
- if (e.guestsCanModify) {
- return ACCESS_LEVEL_EDIT;
- }
-
- if (!TextUtils.isEmpty(calendarOwnerAccount)
- && calendarOwnerAccount.equalsIgnoreCase(e.organizer)) {
- return ACCESS_LEVEL_EDIT;
- }
-
- return ACCESS_LEVEL_DELETE;
- }
-
/**
* Sets mSelectionDay and mSelectionHour based on the (x,y) touch position.
* If the touch position is not within the displayed grid, then this
@@ -4598,20 +3657,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
findSelectedEvent(x, y);
-// Log.i("Cal", "setSelectionFromPosition( " + x + ", " + y + " ) day: " + day + " hour: "
-// + mSelectionHour + " mFirstCell: " + mFirstCell + " mFirstHourOffset: "
-// + mFirstHourOffset);
-// if (mSelectedEvent != null) {
-// Log.i("Cal", " num events: " + mSelectedEvents.size() + " event: "
-// + mSelectedEvent.title);
-// for (Event ev : mSelectedEvents) {
-// int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL
-// | DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
-// String timeRange = formatDateRange(mContext, ev.startMillis, ev.endMillis, flags);
-//
-// Log.i("Cal", " " + timeRange + " " + ev.title);
-// }
-// }
sendAccessibilityEventAsNeeded(true);
// Restore old values
@@ -4945,30 +3990,6 @@ public class DayView extends View implements View.OnCreateContextMenuListener,
@Override
public boolean onLongClick(View v) {
- int flags = DateUtils.FORMAT_SHOW_WEEKDAY;
- long time = getSelectedTimeInMillis();
- if (!mSelectionAllday) {
- flags |= DateUtils.FORMAT_SHOW_TIME;
- }
- if (DateFormat.is24HourFormat(mContext)) {
- flags |= DateUtils.FORMAT_24HOUR;
- }
- mLongPressTitle = Utils.formatDateRange(mContext, time, time, flags);
- new AlertDialog.Builder(mContext).setTitle(mLongPressTitle)
- .setItems(mLongPressItems, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (which == 0) {
- long extraLong = 0;
- if (mSelectionAllday) {
- extraLong = CalendarController.EXTRA_CREATE_ALL_DAY;
- }
- mController.sendEventRelatedEventWithExtra(this,
- EventType.CREATE_EVENT, -1, getSelectedTimeInMillis(), 0, -1,
- -1, extraLong, -1);
- }
- }
- }).show().setCanceledOnTouchOutside(true);
return true;
}
diff --git a/src/com/android/calendar/DeleteEventHelper.java b/src/com/android/calendar/DeleteEventHelper.java
deleted file mode 100644
index c436f5a1..00000000
--- a/src/com/android/calendar/DeleteEventHelper.java
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * Copyright (C) 2008 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 com.android.calendar.event.EditEventHelper;
-import com.android.calendarcommon2.EventRecurrence;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.CalendarContract;
-import android.provider.CalendarContract.Events;
-import android.text.TextUtils;
-import android.text.format.Time;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-/**
- * A helper class for deleting events. If a normal event is selected for
- * deletion, then this pops up a confirmation dialog. If the user confirms,
- * then the normal event is deleted.
- *
- * <p>
- * If a repeating event is selected for deletion, then this pops up dialog
- * asking if the user wants to delete just this one instance, or all the
- * events in the series, or this event plus all following events. The user
- * may also cancel the delete.
- * </p>
- *
- * <p>
- * To use this class, create an instance, passing in the parent activity
- * and a boolean that determines if the parent activity should exit if the
- * event is deleted. Then to use the instance, call one of the
- * {@link delete()} methods on this class.
- *
- * An instance of this class may be created once and reused (by calling
- * {@link #delete()} multiple times).
- */
-public class DeleteEventHelper {
- private final Activity mParent;
- private Context mContext;
-
- private long mStartMillis;
- private long mEndMillis;
- private CalendarEventModel mModel;
-
- /**
- * If true, then call finish() on the parent activity when done.
- */
- private boolean mExitWhenDone;
- // the runnable to execute when the delete is confirmed
- private Runnable mCallback;
-
- /**
- * These are the corresponding indices into the array of strings
- * "R.array.delete_repeating_labels" in the resource file.
- */
- public static final int DELETE_SELECTED = 0;
- public static final int DELETE_ALL_FOLLOWING = 1;
- public static final int DELETE_ALL = 2;
-
- private int mWhichDelete;
- private ArrayList<Integer> mWhichIndex;
- private AlertDialog mAlertDialog;
- private Dialog.OnDismissListener mDismissListener;
-
- private String mSyncId;
-
- private AsyncQueryService mService;
-
- private DeleteNotifyListener mDeleteStartedListener = null;
-
- public interface DeleteNotifyListener {
- public void onDeleteStarted();
- }
-
-
- public DeleteEventHelper(Context context, Activity parentActivity, boolean exitWhenDone) {
- if (exitWhenDone && parentActivity == null) {
- throw new IllegalArgumentException("parentActivity is required to exit when done");
- }
-
- mContext = context;
- mParent = parentActivity;
- // TODO move the creation of this service out into the activity.
- mService = new AsyncQueryService(mContext) {
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- if (cursor == null) {
- return;
- }
- cursor.moveToFirst();
- CalendarEventModel mModel = new CalendarEventModel();
- EditEventHelper.setModelFromCursor(mModel, cursor);
- cursor.close();
- DeleteEventHelper.this.delete(mStartMillis, mEndMillis, mModel, mWhichDelete);
- }
- };
- mExitWhenDone = exitWhenDone;
- }
-
- public void setExitWhenDone(boolean exitWhenDone) {
- mExitWhenDone = exitWhenDone;
- }
-
- /**
- * This callback is used when a normal event is deleted.
- */
- private DialogInterface.OnClickListener mDeleteNormalDialogListener =
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int button) {
- deleteStarted();
- long id = mModel.mId; // mCursor.getInt(mEventIndexId);
- Uri uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, id);
- mService.startDelete(mService.getNextToken(), null, uri, null, null, Utils.UNDO_DELAY);
- if (mCallback != null) {
- mCallback.run();
- }
- if (mExitWhenDone) {
- mParent.finish();
- }
- }
- };
-
- /**
- * This callback is used when an exception to an event is deleted
- */
- private DialogInterface.OnClickListener mDeleteExceptionDialogListener =
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int button) {
- deleteStarted();
- deleteExceptionEvent();
- if (mCallback != null) {
- mCallback.run();
- }
- if (mExitWhenDone) {
- mParent.finish();
- }
- }
- };
-
- /**
- * This callback is used when a list item for a repeating event is selected
- */
- private DialogInterface.OnClickListener mDeleteListListener =
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int button) {
- // set mWhichDelete to the delete type at that index
- mWhichDelete = mWhichIndex.get(button);
-
- // Enable the "ok" button now that the user has selected which
- // events in the series to delete.
- Button ok = mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
- ok.setEnabled(true);
- }
- };
-
- /**
- * This callback is used when a repeating event is deleted.
- */
- private DialogInterface.OnClickListener mDeleteRepeatingDialogListener =
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int button) {
- deleteStarted();
- if (mWhichDelete != -1) {
- deleteRepeatingEvent(mWhichDelete);
- }
- }
- };
-
- /**
- * Does the required processing for deleting an event, which includes
- * first popping up a dialog asking for confirmation (if the event is
- * a normal event) or a dialog asking which events to delete (if the
- * event is a repeating event). The "which" parameter is used to check
- * the initial selection and is only used for repeating events. Set
- * "which" to -1 to have nothing selected initially.
- *
- * @param begin the begin time of the event, in UTC milliseconds
- * @param end the end time of the event, in UTC milliseconds
- * @param eventId the event id
- * @param which one of the values {@link DELETE_SELECTED},
- * {@link DELETE_ALL_FOLLOWING}, {@link DELETE_ALL}, or -1
- */
- public void delete(long begin, long end, long eventId, int which) {
- Uri uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventId);
- mService.startQuery(mService.getNextToken(), null, uri, EditEventHelper.EVENT_PROJECTION,
- null, null, null);
- mStartMillis = begin;
- mEndMillis = end;
- mWhichDelete = which;
- }
-
- public void delete(long begin, long end, long eventId, int which, Runnable callback) {
- delete(begin, end, eventId, which);
- mCallback = callback;
- }
-
- /**
- * Does the required processing for deleting an event. This method
- * takes a {@link CalendarEventModel} object, which must have a valid
- * uri for referencing the event in the database and have the required
- * fields listed below.
- * The required fields for a normal event are:
- *
- * <ul>
- * <li> Events._ID </li>
- * <li> Events.TITLE </li>
- * <li> Events.RRULE </li>
- * </ul>
- *
- * The required fields for a repeating event include the above plus the
- * following fields:
- *
- * <ul>
- * <li> Events.ALL_DAY </li>
- * <li> Events.CALENDAR_ID </li>
- * <li> Events.DTSTART </li>
- * <li> Events._SYNC_ID </li>
- * <li> Events.EVENT_TIMEZONE </li>
- * </ul>
- *
- * If the event no longer exists in the db this will still prompt
- * the user but will return without modifying the db after the query
- * returns.
- *
- * @param begin the begin time of the event, in UTC milliseconds
- * @param end the end time of the event, in UTC milliseconds
- * @param cursor the database cursor containing the required fields
- * @param which one of the values {@link DELETE_SELECTED},
- * {@link DELETE_ALL_FOLLOWING}, {@link DELETE_ALL}, or -1
- */
- public void delete(long begin, long end, CalendarEventModel model, int which) {
- mWhichDelete = which;
- mStartMillis = begin;
- mEndMillis = end;
- mModel = model;
- mSyncId = model.mSyncId;
-
- // If this is a repeating event, then pop up a dialog asking the
- // user if they want to delete all of the repeating events or
- // just some of them.
- String rRule = model.mRrule;
- String originalEvent = model.mOriginalSyncId;
- if (TextUtils.isEmpty(rRule)) {
- AlertDialog dialog = new AlertDialog.Builder(mContext)
- .setMessage(R.string.delete_this_event_title)
- .setIconAttribute(android.R.attr.alertDialogIcon)
- .setNegativeButton(android.R.string.cancel, null).create();
-
- if (originalEvent == null) {
- // This is a normal event. Pop up a confirmation dialog.
- dialog.setButton(DialogInterface.BUTTON_POSITIVE,
- mContext.getText(android.R.string.ok),
- mDeleteNormalDialogListener);
- } else {
- // This is an exception event. Pop up a confirmation dialog.
- dialog.setButton(DialogInterface.BUTTON_POSITIVE,
- mContext.getText(android.R.string.ok),
- mDeleteExceptionDialogListener);
- }
- dialog.setOnDismissListener(mDismissListener);
- dialog.show();
- mAlertDialog = dialog;
- } else {
- // This is a repeating event. Pop up a dialog asking which events
- // to delete.
- Resources res = mContext.getResources();
- ArrayList<String> labelArray = new ArrayList<String>(Arrays.asList(res
- .getStringArray(R.array.delete_repeating_labels)));
- // asList doesn't like int[] so creating it manually.
- int[] labelValues = res.getIntArray(R.array.delete_repeating_values);
- ArrayList<Integer> labelIndex = new ArrayList<Integer>();
- for (int val : labelValues) {
- labelIndex.add(val);
- }
-
- if (mSyncId == null) {
- // remove 'Only this event' item
- labelArray.remove(0);
- labelIndex.remove(0);
- if (!model.mIsOrganizer) {
- // remove 'This and future events' item
- labelArray.remove(0);
- labelIndex.remove(0);
- }
- } else if (!model.mIsOrganizer) {
- // remove 'This and future events' item
- labelArray.remove(1);
- labelIndex.remove(1);
- }
- if (which != -1) {
- // transform the which to the index in the array
- which = labelIndex.indexOf(which);
- }
- mWhichIndex = labelIndex;
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext,
- android.R.layout.simple_list_item_single_choice, labelArray);
- AlertDialog dialog = new AlertDialog.Builder(mContext)
- .setTitle(
- mContext.getString(R.string.delete_recurring_event_title,model.mTitle))
- .setIconAttribute(android.R.attr.alertDialogIcon)
- .setSingleChoiceItems(adapter, which, mDeleteListListener)
- .setPositiveButton(android.R.string.ok, mDeleteRepeatingDialogListener)
- .setNegativeButton(android.R.string.cancel, null).show();
- dialog.setOnDismissListener(mDismissListener);
- mAlertDialog = dialog;
-
- if (which == -1) {
- // Disable the "Ok" button until the user selects which events
- // to delete.
- Button ok = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
- ok.setEnabled(false);
- }
- }
- }
-
- private void deleteExceptionEvent() {
- long id = mModel.mId; // mCursor.getInt(mEventIndexId);
-
- // update a recurrence exception by setting its status to "canceled"
- ContentValues values = new ContentValues();
- values.put(Events.STATUS, Events.STATUS_CANCELED);
-
- Uri uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, id);
- mService.startUpdate(mService.getNextToken(), null, uri, values, null, null,
- Utils.UNDO_DELAY);
- }
-
- private void deleteRepeatingEvent(int which) {
- String rRule = mModel.mRrule;
- boolean allDay = mModel.mAllDay;
- long dtstart = mModel.mStart;
- long id = mModel.mId; // mCursor.getInt(mEventIndexId);
-
- switch (which) {
- case DELETE_SELECTED: {
- // If we are deleting the first event in the series, then
- // instead of creating a recurrence exception, just change
- // the start time of the recurrence.
- if (dtstart == mStartMillis) {
- // TODO
- }
-
- // Create a recurrence exception by creating a new event
- // with the status "cancelled".
- ContentValues values = new ContentValues();
-
- // The title might not be necessary, but it makes it easier
- // to find this entry in the database when there is a problem.
- String title = mModel.mTitle;
- values.put(Events.TITLE, title);
-
- String timezone = mModel.mTimezone;
- long calendarId = mModel.mCalendarId;
- values.put(Events.EVENT_TIMEZONE, timezone);
- values.put(Events.ALL_DAY, allDay ? 1 : 0);
- values.put(Events.ORIGINAL_ALL_DAY, allDay ? 1 : 0);
- values.put(Events.CALENDAR_ID, calendarId);
- values.put(Events.DTSTART, mStartMillis);
- values.put(Events.DTEND, mEndMillis);
- values.put(Events.ORIGINAL_SYNC_ID, mSyncId);
- values.put(Events.ORIGINAL_ID, id);
- values.put(Events.ORIGINAL_INSTANCE_TIME, mStartMillis);
- values.put(Events.STATUS, Events.STATUS_CANCELED);
-
- mService.startInsert(mService.getNextToken(), null, Events.CONTENT_URI, values,
- Utils.UNDO_DELAY);
- break;
- }
- case DELETE_ALL: {
- Uri uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, id);
- mService.startDelete(mService.getNextToken(), null, uri, null, null,
- Utils.UNDO_DELAY);
- break;
- }
- case DELETE_ALL_FOLLOWING: {
- // If we are deleting the first event in the series and all
- // following events, then delete them all.
- if (dtstart == mStartMillis) {
- Uri uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, id);
- mService.startDelete(mService.getNextToken(), null, uri, null, null,
- Utils.UNDO_DELAY);
- break;
- }
-
- // Modify the repeating event to end just before this event time
- EventRecurrence eventRecurrence = new EventRecurrence();
- eventRecurrence.parse(rRule);
- Time date = new Time();
- if (allDay) {
- date.timezone = Time.TIMEZONE_UTC;
- }
- date.set(mStartMillis);
- date.second--;
- date.normalize(false);
-
- // Google calendar seems to require the UNTIL string to be
- // in UTC.
- date.switchTimezone(Time.TIMEZONE_UTC);
- eventRecurrence.until = date.format2445();
-
- ContentValues values = new ContentValues();
- values.put(Events.DTSTART, dtstart);
- values.put(Events.RRULE, eventRecurrence.toString());
- Uri uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, id);
- mService.startUpdate(mService.getNextToken(), null, uri, values, null, null,
- Utils.UNDO_DELAY);
- break;
- }
- }
- if (mCallback != null) {
- mCallback.run();
- }
- if (mExitWhenDone) {
- mParent.finish();
- }
- }
-
- public void setDeleteNotificationListener(DeleteNotifyListener listener) {
- mDeleteStartedListener = listener;
- }
-
- private void deleteStarted() {
- if (mDeleteStartedListener != null) {
- mDeleteStartedListener.onDeleteStarted();
- }
- }
-
- public void setOnDismissListener(Dialog.OnDismissListener listener) {
- if (mAlertDialog != null) {
- mAlertDialog.setOnDismissListener(listener);
- }
- mDismissListener = listener;
- }
-
- public void dismissAlertDialog() {
- if (mAlertDialog != null) {
- mAlertDialog.dismiss();
- }
- }
-}
diff --git a/src/com/android/calendar/EditResponseHelper.java b/src/com/android/calendar/EditResponseHelper.java
deleted file mode 100644
index 1f32ce01..00000000
--- a/src/com/android/calendar/EditResponseHelper.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * 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.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnDismissListener;
-import android.widget.Button;
-
-/**
- * A helper class for editing the response to an invitation when the invitation
- * is a repeating event.
- */
-public class EditResponseHelper implements DialogInterface.OnClickListener, OnDismissListener {
- private final Activity mParent;
- private int mWhichEvents = -1;
- private AlertDialog mAlertDialog;
- private boolean mClickedOk = false;
-
- /**
- * This callback is passed in to this object when this object is created
- * and is invoked when the "Ok" button is selected.
- */
- private DialogInterface.OnClickListener mDialogListener;
-
- public EditResponseHelper(Activity parent) {
- mParent = parent;
- }
-
- public void setOnClickListener(DialogInterface.OnClickListener listener) {
- mDialogListener = listener;
- }
-
- /**
- * @return whichEvents, representing which events were selected on which to
- * apply the response:
- * -1 means no choice selected, or the dialog was
- * canceled.
- * 0 means just the single event.
- * 1 means all events.
- */
- public int getWhichEvents() {
- return mWhichEvents;
- }
-
- public void setWhichEvents(int which) {
- mWhichEvents = which;
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- setClickedOk(true);
- }
-
- @Override
- public void onDismiss(DialogInterface dialog) {
- // If the click was not "OK", clear out whichEvents to represent
- // that the dialog was canceled.
- if (!getClickedOk()) {
- setWhichEvents(-1);
- }
- setClickedOk(false);
-
- // Call the pre-set dismiss listener too.
- if (mDismissListener != null) {
- mDismissListener.onDismiss(dialog);
- }
-
- }
-
- private boolean getClickedOk() {
- return mClickedOk;
- }
-
- private void setClickedOk(boolean clickedOk) {
- mClickedOk = clickedOk;
- }
-
- /**
- * This callback is used when a list item is selected
- */
- private DialogInterface.OnClickListener mListListener =
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- mWhichEvents = which;
-
- // Enable the "ok" button now that the user has selected which
- // events in the series to delete.
- Button ok = mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
- ok.setEnabled(true);
- }
- };
-
- private DialogInterface.OnDismissListener mDismissListener;
-
-
- /**
- * Set the dismiss listener to be called when the dialog is ended. There,
- * use getWhichEvents() to see how the dialog was dismissed; if it returns
- * -1, the dialog was canceled out. If it is not -1, it's the index of
- * which events the user wants to respond to.
- * @param onDismissListener
- */
- public void setDismissListener(OnDismissListener onDismissListener) {
- mDismissListener = onDismissListener;
- }
-
- public void showDialog(int whichEvents) {
- // We need to have a non-null listener, otherwise we get null when
- // we try to fetch the "Ok" button.
- if (mDialogListener == null) {
- mDialogListener = this;
- }
- AlertDialog dialog = new AlertDialog.Builder(mParent).setTitle(
- R.string.change_response_title).setIconAttribute(android.R.attr.alertDialogIcon)
- .setSingleChoiceItems(R.array.change_response_labels, whichEvents, mListListener)
- .setPositiveButton(android.R.string.ok, mDialogListener)
- .setNegativeButton(android.R.string.cancel, null).show();
- // The caller may set a dismiss listener to hear back when the dialog is
- // finished. Use getWhichEvents() to see how the dialog was dismissed.
- dialog.setOnDismissListener(this);
- mAlertDialog = dialog;
-
- if (whichEvents == -1) {
- // Disable the "Ok" button until the user selects which events to
- // delete.
- Button ok = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
- ok.setEnabled(false);
- }
- }
-
- public void dismissAlertDialog() {
- if (mAlertDialog != null) {
- mAlertDialog.dismiss();
- }
- }
-
-}
diff --git a/src/com/android/calendar/EmailAddressAdapter.java b/src/com/android/calendar/EmailAddressAdapter.java
deleted file mode 100644
index 1f8519bb..00000000
--- a/src/com/android/calendar/EmailAddressAdapter.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.calendar;
-
-import com.android.common.contacts.BaseEmailAddressAdapter;
-import com.android.ex.chips.AccountSpecifier;
-
-import android.content.Context;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-/**
-* An adaptation of {@link BaseEmailAddressAdapter} for the Email app. The main
-* purpose of the class is to bind the generic implementation to the resources
-* defined locally: strings and layouts.
-*/
-public class EmailAddressAdapter extends BaseEmailAddressAdapter implements AccountSpecifier {
-
- private LayoutInflater mInflater;
-
- public EmailAddressAdapter(Context context) {
- super(context);
- mInflater = LayoutInflater.from(context);
- }
-
- @Override
- protected View inflateItemView(ViewGroup parent) {
- return mInflater.inflate(R.layout.email_autocomplete_item, parent, false);
- }
-
- @Override
- protected View inflateItemViewLoading(ViewGroup parent) {
- return mInflater.inflate(R.layout.email_autocomplete_item_loading, parent, false);
- }
-
- @Override
- protected void bindView(View view, String directoryType, String directoryName,
- String displayName, String emailAddress) {
- TextView text1 = (TextView)view.findViewById(R.id.text1);
- TextView text2 = (TextView)view.findViewById(R.id.text2);
- text1.setText(displayName);
- text2.setText(emailAddress);
- }
-
- @Override
- protected void bindViewLoading(View view, String directoryType, String directoryName) {
- TextView text1 = (TextView)view.findViewById(R.id.text1);
- String text = getContext().getString(R.string.directory_searching_fmt,
- TextUtils.isEmpty(directoryName) ? directoryType : directoryName);
- text1.setText(text);
- }
-}
diff --git a/src/com/android/calendar/EventInfoActivity.java b/src/com/android/calendar/EventInfoActivity.java
index 9b136bd0..626e099d 100644
--- a/src/com/android/calendar/EventInfoActivity.java
+++ b/src/com/android/calendar/EventInfoActivity.java
@@ -34,15 +34,10 @@ import android.provider.CalendarContract.Attendees;
import android.util.Log;
import android.widget.Toast;
-import com.android.calendar.CalendarEventModel.ReminderEntry;
-
import java.util.ArrayList;
import java.util.List;
public class EventInfoActivity extends Activity {
-// implements CalendarController.EventHandler, SearchView.OnQueryTextListener,
-// SearchView.OnCloseListener {
-
private static final String TAG = "EventInfoActivity";
private EventInfoFragment mInfoFragment;
private long mStartMillis, mEndMillis;
@@ -74,7 +69,6 @@ public class EventInfoActivity extends Activity {
int attendeeResponse = 0;
mEventId = -1;
boolean isDialog = false;
- ArrayList<ReminderEntry> reminders = null;
if (icicle != null) {
mEventId = icicle.getLong(EventInfoFragment.BUNDLE_KEY_EVENT_ID);
@@ -82,8 +76,6 @@ public class EventInfoActivity extends Activity {
mEndMillis = icicle.getLong(EventInfoFragment.BUNDLE_KEY_END_MILLIS);
attendeeResponse = icicle.getInt(EventInfoFragment.BUNDLE_KEY_ATTENDEE_RESPONSE);
isDialog = icicle.getBoolean(EventInfoFragment.BUNDLE_KEY_IS_DIALOG);
-
- reminders = Utils.readRemindersFromBundle(icicle);
} else if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
mStartMillis = intent.getLongExtra(EXTRA_EVENT_BEGIN_TIME, 0);
mEndMillis = intent.getLongExtra(EXTRA_EVENT_END_TIME, 0);
@@ -155,8 +147,7 @@ public class EventInfoActivity extends Activity {
mInfoFragment = new EventInfoFragment(this, mEventId, mStartMillis, mEndMillis,
attendeeResponse, isDialog, (isDialog ?
EventInfoFragment.DIALOG_WINDOW_STYLE :
- EventInfoFragment.FULL_WINDOW_STYLE),
- reminders);
+ EventInfoFragment.FULL_WINDOW_STYLE));
ft.replace(R.id.main_frame, mInfoFragment);
ft.commit();
}
diff --git a/src/com/android/calendar/EventInfoFragment.java b/src/com/android/calendar/EventInfoFragment.java
index e73482cf..b95c7c3d 100644
--- a/src/com/android/calendar/EventInfoFragment.java
+++ b/src/com/android/calendar/EventInfoFragment.java
@@ -51,7 +51,6 @@ import android.os.Bundle;
import android.provider.CalendarContract;
import android.provider.CalendarContract.Attendees;
import android.provider.CalendarContract.Calendars;
-import android.provider.CalendarContract.Colors;
import android.provider.CalendarContract.Events;
import android.provider.CalendarContract.Reminders;
import android.provider.ContactsContract;
@@ -95,18 +94,10 @@ import android.widget.Toast;
import com.android.calendar.CalendarController.EventInfo;
import com.android.calendar.CalendarController.EventType;
-import com.android.calendar.CalendarEventModel.Attendee;
-import com.android.calendar.CalendarEventModel.ReminderEntry;
import com.android.calendar.alerts.QuickResponseActivity;
-import com.android.calendar.event.AttendeesView;
-import com.android.calendar.event.EditEventActivity;
-import com.android.calendar.event.EditEventHelper;
-import com.android.calendar.event.EventColorPickerDialog;
-import com.android.calendar.event.EventViewUtils;
import com.android.calendarcommon2.DateException;
import com.android.calendarcommon2.Duration;
import com.android.calendarcommon2.EventRecurrence;
-import com.android.colorpicker.ColorPickerSwatch.OnColorSelectedListener;
import com.android.colorpicker.HsvColorComparator;
import java.util.ArrayList;
@@ -115,15 +106,11 @@ import java.util.Collections;
import java.util.List;
public class EventInfoFragment extends DialogFragment implements OnCheckedChangeListener,
- CalendarController.EventHandler, OnClickListener, DeleteEventHelper.DeleteNotifyListener,
- OnColorSelectedListener {
+ CalendarController.EventHandler, OnClickListener {
public static final boolean DEBUG = false;
public static final String TAG = "EventInfoFragment";
- public static final String COLOR_PICKER_DIALOG_TAG = "EventColorPickerDialog";
-
- private static final int REQUEST_CODE_COLOR_PICKER = 0;
protected static final String BUNDLE_KEY_EVENT_ID = "key_event_id";
protected static final String BUNDLE_KEY_START_MILLIS = "key_start_millis";
@@ -228,49 +215,13 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
private static final int EVENT_INDEX_DTEND = 20;
private static final int EVENT_INDEX_DURATION = 21;
- private static final String[] ATTENDEES_PROJECTION = new String[] {
- Attendees._ID, // 0
- Attendees.ATTENDEE_NAME, // 1
- Attendees.ATTENDEE_EMAIL, // 2
- Attendees.ATTENDEE_RELATIONSHIP, // 3
- Attendees.ATTENDEE_STATUS, // 4
- Attendees.ATTENDEE_IDENTITY, // 5
- Attendees.ATTENDEE_ID_NAMESPACE // 6
- };
- private static final int ATTENDEES_INDEX_ID = 0;
- private static final int ATTENDEES_INDEX_NAME = 1;
- private static final int ATTENDEES_INDEX_EMAIL = 2;
- private static final int ATTENDEES_INDEX_RELATIONSHIP = 3;
- private static final int ATTENDEES_INDEX_STATUS = 4;
- private static final int ATTENDEES_INDEX_IDENTITY = 5;
- private static final int ATTENDEES_INDEX_ID_NAMESPACE = 6;
-
static {
if (!Utils.isJellybeanOrLater()) {
EVENT_PROJECTION[EVENT_INDEX_CUSTOM_APP_PACKAGE] = Events._ID; // dummy value
EVENT_PROJECTION[EVENT_INDEX_CUSTOM_APP_URI] = Events._ID; // dummy value
-
- ATTENDEES_PROJECTION[ATTENDEES_INDEX_IDENTITY] = Attendees._ID; // dummy value
- ATTENDEES_PROJECTION[ATTENDEES_INDEX_ID_NAMESPACE] = Attendees._ID; // dummy value
}
}
- private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=?";
-
- private static final String ATTENDEES_SORT_ORDER = Attendees.ATTENDEE_NAME + " ASC, "
- + Attendees.ATTENDEE_EMAIL + " ASC";
-
- private static final String[] REMINDERS_PROJECTION = new String[] {
- Reminders._ID, // 0
- Reminders.MINUTES, // 1
- Reminders.METHOD // 2
- };
- private static final int REMINDERS_INDEX_ID = 0;
- private static final int REMINDERS_MINUTES_ID = 1;
- private static final int REMINDERS_METHOD_ID = 2;
-
- private static final String REMINDERS_WHERE = Reminders.EVENT_ID + "=?";
-
static final String[] CALENDARS_PROJECTION = new String[] {
Calendars._ID, // 0
Calendars.CALENDAR_DISPLAY_NAME, // 1
@@ -289,15 +240,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
static final String CALENDARS_DUPLICATE_NAME_WHERE = Calendars.CALENDAR_DISPLAY_NAME + "=?";
static final String CALENDARS_VISIBLE_WHERE = Calendars.VISIBLE + "=?";
- static final String[] COLORS_PROJECTION = new String[] {
- Colors._ID, // 0
- Colors.COLOR, // 1
- Colors.COLOR_KEY // 2
- };
-
- static final String COLORS_WHERE = Colors.ACCOUNT_NAME + "=? AND " + Colors.ACCOUNT_TYPE +
- "=? AND " + Colors.COLOR_TYPE + "=" + Colors.TYPE_EVENT;
-
public static final int COLORS_INDEX_COLOR = 1;
public static final int COLORS_INDEX_COLOR_KEY = 2;
@@ -306,9 +248,7 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
private Uri mUri;
private long mEventId;
private Cursor mEventCursor;
- private Cursor mAttendeesCursor;
private Cursor mCalendarsCursor;
- private Cursor mRemindersCursor;
private static float mScale = 0; // Used for supporting different screen densities
@@ -318,21 +258,10 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
private long mEndMillis;
private boolean mAllDay;
- private boolean mHasAttendeeData;
- private String mEventOrganizerEmail;
- private String mEventOrganizerDisplayName = "";
- private boolean mIsOrganizer;
- private long mCalendarOwnerAttendeeId = EditEventHelper.ATTENDEE_ID_NONE;
private boolean mOwnerCanRespond;
private String mSyncAccountName;
private String mCalendarOwnerAccount;
- private boolean mCanModifyCalendar;
- private boolean mCanModifyEvent;
private boolean mIsBusyFreeCalendar;
- private int mNumOfAttendees;
- private EditResponseHelper mEditResponseHelper;
- private boolean mDeleteDialogVisible = false;
- private DeleteEventHelper mDeleteHelper;
private int mOriginalAttendeeResponse;
private int mAttendeeResponseFromIntent = Attendees.ATTENDEE_STATUS_NONE;
@@ -341,19 +270,13 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
// Used as the temporary response until the dialog is confirmed. It is also
// able to be used as a state marker for configuration changes.
private int mTentativeUserSetResponse = Attendees.ATTENDEE_STATUS_NONE;
- private boolean mIsRepeating;
private boolean mHasAlarm;
- private int mMaxReminders;
- private String mCalendarAllowedReminders;
// Used to prevent saving changes in event if it is being deleted.
private boolean mEventDeletionStarted = false;
private TextView mTitle;
private TextView mWhenDateTime;
private TextView mWhere;
- private ExpandableTextView mDesc;
- private AttendeesView mLongAttendees;
- private Button emailAttendeesButton;
private Menu mMenu = null;
private View mHeadlines;
private ScrollView mScrollView;
@@ -362,9 +285,7 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
private ObjectAnimator mAnimateAlpha;
private long mLoadingMsgStartTime;
- private EventColorPickerDialog mColorPickerDialog;
private SparseIntArray mDisplayColorKeyMap = new SparseIntArray();
- private int[] mColors;
private int mOriginalColor = -1;
private boolean mOriginalColorInitialized = false;
private int mCalendarColor = -1;
@@ -379,37 +300,9 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
private boolean mNoCrossFade = false; // Used to prevent repeated cross-fade
private RadioGroup mResponseRadioGroup;
- ArrayList<Attendee> mAcceptedAttendees = new ArrayList<Attendee>();
- ArrayList<Attendee> mDeclinedAttendees = new ArrayList<Attendee>();
- ArrayList<Attendee> mTentativeAttendees = new ArrayList<Attendee>();
- ArrayList<Attendee> mNoResponseAttendees = new ArrayList<Attendee>();
ArrayList<String> mToEmails = new ArrayList<String>();
ArrayList<String> mCcEmails = new ArrayList<String>();
- private int mDefaultReminderMinutes;
- private final ArrayList<LinearLayout> mReminderViews = new ArrayList<LinearLayout>(0);
- public ArrayList<ReminderEntry> mReminders;
- public ArrayList<ReminderEntry> mOriginalReminders = new ArrayList<ReminderEntry>();
- public ArrayList<ReminderEntry> mUnsupportedReminders = new ArrayList<ReminderEntry>();
- private boolean mUserModifiedReminders = false;
-
- /**
- * Contents of the "minutes" spinner. This has default values from the XML file, augmented
- * with any additional values that were already associated with the event.
- */
- private ArrayList<Integer> mReminderMinuteValues;
- private ArrayList<String> mReminderMinuteLabels;
-
- /**
- * Contents of the "methods" spinner. The "values" list specifies the method constant
- * (e.g. {@link Reminders#METHOD_ALERT}) associated with the labels. Any methods that
- * aren't allowed by the Calendar will be removed.
- */
- private ArrayList<Integer> mReminderMethodValues;
- private ArrayList<String> mReminderMethodLabels;
-
- private QueryHandler mHandler;
-
private final Runnable mTZUpdater = new Runnable() {
@Override
@@ -430,8 +323,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
}
};
- private OnItemSelectedListener mReminderChangeListener;
-
private static int mDialogWidth = 500;
private static int mDialogHeight = 600;
private static int DIALOG_TOP_MARGIN = 8;
@@ -447,191 +338,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
private CalendarController mController;
- private class QueryHandler extends AsyncQueryService {
- public QueryHandler(Context context) {
- super(context);
- }
-
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- // if the activity is finishing, then close the cursor and return
- final Activity activity = getActivity();
- if (activity == null || activity.isFinishing()) {
- if (cursor != null) {
- cursor.close();
- }
- return;
- }
-
- switch (token) {
- case TOKEN_QUERY_EVENT:
- mEventCursor = Utils.matrixCursorFromCursor(cursor);
- if (!initEventCursor()) {
- displayEventNotFound();
- return;
- }
- if (!mCalendarColorInitialized) {
- mCalendarColor = Utils.getDisplayColorFromColor(
- mEventCursor.getInt(EVENT_INDEX_CALENDAR_COLOR));
- mCalendarColorInitialized = true;
- }
-
- if (!mOriginalColorInitialized) {
- mOriginalColor = mEventCursor.isNull(EVENT_INDEX_EVENT_COLOR)
- ? mCalendarColor : Utils.getDisplayColorFromColor(
- mEventCursor.getInt(EVENT_INDEX_EVENT_COLOR));
- mOriginalColorInitialized = true;
- }
-
- if (!mCurrentColorInitialized) {
- mCurrentColor = mOriginalColor;
- mCurrentColorInitialized = true;
- }
-
- updateEvent(mView);
- prepareReminders();
-
- // start calendar query
- Uri uri = Calendars.CONTENT_URI;
- String[] args = new String[] {
- Long.toString(mEventCursor.getLong(EVENT_INDEX_CALENDAR_ID))};
- startQuery(TOKEN_QUERY_CALENDARS, null, uri, CALENDARS_PROJECTION,
- CALENDARS_WHERE, args, null);
- break;
- case TOKEN_QUERY_CALENDARS:
- mCalendarsCursor = Utils.matrixCursorFromCursor(cursor);
- updateCalendar(mView);
- // FRAG_TODO fragments shouldn't set the title anymore
- updateTitle();
-
- args = new String[] {
- mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_NAME),
- mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_TYPE) };
- uri = Colors.CONTENT_URI;
- startQuery(TOKEN_QUERY_COLORS, null, uri, COLORS_PROJECTION, COLORS_WHERE, args,
- null);
-
- if (!mIsBusyFreeCalendar) {
- args = new String[] { Long.toString(mEventId) };
-
- // start attendees query
- uri = Attendees.CONTENT_URI;
- startQuery(TOKEN_QUERY_ATTENDEES, null, uri, ATTENDEES_PROJECTION,
- ATTENDEES_WHERE, args, ATTENDEES_SORT_ORDER);
- } else {
- sendAccessibilityEventIfQueryDone(TOKEN_QUERY_ATTENDEES);
- }
- if (mHasAlarm) {
- // start reminders query
- args = new String[] { Long.toString(mEventId) };
- uri = Reminders.CONTENT_URI;
- startQuery(TOKEN_QUERY_REMINDERS, null, uri,
- REMINDERS_PROJECTION, REMINDERS_WHERE, args, null);
- } else {
- sendAccessibilityEventIfQueryDone(TOKEN_QUERY_REMINDERS);
- }
- break;
- case TOKEN_QUERY_COLORS:
- ArrayList<Integer> colors = new ArrayList<Integer>();
- if (cursor.moveToFirst()) {
- do
- {
- int colorKey = cursor.getInt(COLORS_INDEX_COLOR_KEY);
- int rawColor = cursor.getInt(COLORS_INDEX_COLOR);
- int displayColor = Utils.getDisplayColorFromColor(rawColor);
- mDisplayColorKeyMap.put(displayColor, colorKey);
- colors.add(displayColor);
- } while (cursor.moveToNext());
- }
- cursor.close();
- Integer[] sortedColors = new Integer[colors.size()];
- Arrays.sort(colors.toArray(sortedColors), new HsvColorComparator());
- mColors = new int[sortedColors.length];
- for (int i = 0; i < sortedColors.length; i++) {
- mColors[i] = sortedColors[i].intValue();
-
- float[] hsv = new float[3];
- Color.colorToHSV(mColors[i], hsv);
- if (DEBUG) {
- Log.d("Color", "H:" + hsv[0] + ",S:" + hsv[1] + ",V:" + hsv[2]);
- }
- }
- if (mCanModifyCalendar) {
- View button = mView.findViewById(R.id.change_color);
- if (button != null && mColors.length > 0) {
- button.setEnabled(true);
- button.setVisibility(View.VISIBLE);
- }
- }
- updateMenu();
- break;
- case TOKEN_QUERY_ATTENDEES:
- mAttendeesCursor = Utils.matrixCursorFromCursor(cursor);
- initAttendeesCursor(mView);
- updateResponse(mView);
- break;
- case TOKEN_QUERY_REMINDERS:
- mRemindersCursor = Utils.matrixCursorFromCursor(cursor);
- initReminders(mView, mRemindersCursor);
- break;
- case TOKEN_QUERY_VISIBLE_CALENDARS:
- if (cursor.getCount() > 1) {
- // Start duplicate calendars query to detect whether to add the calendar
- // email to the calendar owner display.
- String displayName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
- mHandler.startQuery(TOKEN_QUERY_DUPLICATE_CALENDARS, null,
- Calendars.CONTENT_URI, CALENDARS_PROJECTION,
- CALENDARS_DUPLICATE_NAME_WHERE, new String[] {displayName}, null);
- } else {
- // Don't need to display the calendar owner when there is only a single
- // calendar. Skip the duplicate calendars query.
- setVisibilityCommon(mView, R.id.calendar_container, View.GONE);
- mCurrentQuery |= TOKEN_QUERY_DUPLICATE_CALENDARS;
- }
- break;
- case TOKEN_QUERY_DUPLICATE_CALENDARS:
- SpannableStringBuilder sb = new SpannableStringBuilder();
-
- // Calendar display name
- String calendarName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
- sb.append(calendarName);
-
- // Show email account if display name is not unique and
- // display name != email
- String email = mCalendarsCursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
- if (cursor.getCount() > 1 && !calendarName.equalsIgnoreCase(email) &&
- Utils.isValidEmail(email)) {
- sb.append(" (").append(email).append(")");
- }
-
- setVisibilityCommon(mView, R.id.calendar_container, View.VISIBLE);
- setTextCommon(mView, R.id.calendar_name, sb);
- break;
- }
- cursor.close();
- sendAccessibilityEventIfQueryDone(token);
-
- // All queries are done, show the view.
- if (mCurrentQuery == TOKEN_QUERY_ALL) {
- if (mLoadingMsgView.getAlpha() == 1) {
- // Loading message is showing, let it stay a bit more (to prevent
- // flashing) by adding a start delay to the event animation
- long timeDiff = LOADING_MSG_MIN_DISPLAY_TIME - (System.currentTimeMillis() -
- mLoadingMsgStartTime);
- if (timeDiff > 0) {
- mAnimateAlpha.setStartDelay(timeDiff);
- }
- }
- if (!mAnimateAlpha.isRunning() &&!mAnimateAlpha.isStarted() && !mNoCrossFade) {
- mAnimateAlpha.start();
- } else {
- mScrollView.setAlpha(1);
- mLoadingMsgView.setVisibility(View.GONE);
- }
- }
- }
- }
-
private void sendAccessibilityEventIfQueryDone(int token) {
mCurrentQuery |= token;
if (mCurrentQuery == TOKEN_QUERY_ALL) {
@@ -640,8 +346,7 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
}
public EventInfoFragment(Context context, Uri uri, long startMillis, long endMillis,
- int attendeeResponse, boolean isDialog, int windowStyle,
- ArrayList<ReminderEntry> reminders) {
+ int attendeeResponse, boolean isDialog, int windowStyle) {
Resources r = context.getResources();
if (mScale == 0) {
@@ -664,11 +369,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
mEndMillis = endMillis;
mAttendeeResponseFromIntent = attendeeResponse;
mWindowStyle = windowStyle;
-
- // Pass in null if no reminders are being specified.
- // This may be used to explicitly show certain reminders already known
- // about, such as during configuration changes.
- mReminders = reminders;
}
// This is currently required by the fragment manager.
@@ -676,10 +376,9 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
}
public EventInfoFragment(Context context, long eventId, long startMillis, long endMillis,
- int attendeeResponse, boolean isDialog, int windowStyle,
- ArrayList<ReminderEntry> reminders) {
+ int attendeeResponse, boolean isDialog, int windowStyle) {
this(context, ContentUris.withAppendedId(Events.CONTENT_URI, eventId), startMillis,
- endMillis, attendeeResponse, isDialog, windowStyle, reminders);
+ endMillis, attendeeResponse, isDialog, windowStyle);
mEventId = eventId;
}
@@ -687,40 +386,12 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- mReminderChangeListener = new OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- Integer prevValue = (Integer) parent.getTag();
- if (prevValue == null || prevValue != position) {
- parent.setTag(position);
- mUserModifiedReminders = true;
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- // do nothing
- }
-
- };
-
- if (savedInstanceState != null) {
- mIsDialog = savedInstanceState.getBoolean(BUNDLE_KEY_IS_DIALOG, false);
- mWindowStyle = savedInstanceState.getInt(BUNDLE_KEY_WINDOW_STYLE,
- DIALOG_WINDOW_STYLE);
- }
-
if (mIsDialog) {
applyDialogParams();
}
final Activity activity = getActivity();
mContext = activity;
- mColorPickerDialog = (EventColorPickerDialog) activity.getFragmentManager()
- .findFragmentByTag(COLOR_PICKER_DIALOG_TAG);
- if (mColorPickerDialog != null) {
- mColorPickerDialog.setOnColorSelectedListener(this);
- }
}
private void applyDialogParams() {
@@ -760,30 +431,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
// Implements OnCheckedChangeListener
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
- // If we haven't finished the return from the dialog yet, don't display.
- if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
- return;
- }
-
- // If this is not a repeating event, then don't display the dialog
- // asking which events to change.
- int response = getResponseFromButtonId(checkedId);
- if (!mIsRepeating) {
- mUserSetResponse = response;
- return;
- }
-
- // If the selection is the same as the original, then don't display the
- // dialog asking which events to change.
- if (checkedId == findButtonIdForResponse(mOriginalAttendeeResponse)) {
- mUserSetResponse = response;
- return;
- }
-
- // This is a repeating event. We need to ask the user if they mean to
- // change just this one instance or all instances.
- mTentativeUserSetResponse = response;
- mEditResponseHelper.showDialog(mWhichEvents);
}
public void onNothingSelected(AdapterView<?> parent) {
@@ -803,52 +450,7 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
mIsTabletConfig = Utils.getConfigBool(mActivity, R.bool.tablet_config);
mController = CalendarController.getInstance(mActivity);
mController.registerEventHandler(R.layout.event_info, this);
- mEditResponseHelper = new EditResponseHelper(activity);
- mEditResponseHelper.setDismissListener(
- new DialogInterface.OnDismissListener() {
- @Override
- public void onDismiss(DialogInterface dialog) {
- // If the user dismisses the dialog (without hitting OK),
- // then we want to revert the selection that opened the dialog.
- if (mEditResponseHelper.getWhichEvents() != -1) {
- mUserSetResponse = mTentativeUserSetResponse;
- mWhichEvents = mEditResponseHelper.getWhichEvents();
- } else {
- // Revert the attending response radio selection to whatever
- // was selected prior to this selection (possibly nothing).
- int oldResponse;
- if (mUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
- oldResponse = mUserSetResponse;
- } else {
- oldResponse = mOriginalAttendeeResponse;
- }
- int buttonToCheck = findButtonIdForResponse(oldResponse);
-
- if (mResponseRadioGroup != null) {
- mResponseRadioGroup.check(buttonToCheck);
- }
-
- // If the radio group is being cleared, also clear the
- // dialog's selection of which events should be included
- // in this response.
- if (buttonToCheck == -1) {
- mEditResponseHelper.setWhichEvents(-1);
- }
- }
- // Since OnPause will force the dialog to dismiss, do
- // not change the dialog status
- if (!mIsPaused) {
- mTentativeUserSetResponse = Attendees.ATTENDEE_STATUS_NONE;
- }
- }
- });
-
- if (mAttendeeResponseFromIntent != Attendees.ATTENDEE_STATUS_NONE) {
- mEditResponseHelper.setWhichEvents(UPDATE_ALL);
- mWhichEvents = mEditResponseHelper.getWhichEvents();
- }
- mHandler = new QueryHandler(activity);
if (!mIsDialog) {
setHasOptionsMenu(true);
}
@@ -857,47 +459,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
-
- if (savedInstanceState != null) {
- mIsDialog = savedInstanceState.getBoolean(BUNDLE_KEY_IS_DIALOG, false);
- mWindowStyle = savedInstanceState.getInt(BUNDLE_KEY_WINDOW_STYLE,
- DIALOG_WINDOW_STYLE);
- mDeleteDialogVisible =
- savedInstanceState.getBoolean(BUNDLE_KEY_DELETE_DIALOG_VISIBLE,false);
- mCalendarColor = savedInstanceState.getInt(BUNDLE_KEY_CALENDAR_COLOR);
- mCalendarColorInitialized =
- savedInstanceState.getBoolean(BUNDLE_KEY_CALENDAR_COLOR_INIT);
- mOriginalColor = savedInstanceState.getInt(BUNDLE_KEY_ORIGINAL_COLOR);
- mOriginalColorInitialized = savedInstanceState.getBoolean(
- BUNDLE_KEY_ORIGINAL_COLOR_INIT);
- mCurrentColor = savedInstanceState.getInt(BUNDLE_KEY_CURRENT_COLOR);
- mCurrentColorInitialized = savedInstanceState.getBoolean(
- BUNDLE_KEY_CURRENT_COLOR_INIT);
- mCurrentColorKey = savedInstanceState.getInt(BUNDLE_KEY_CURRENT_COLOR_KEY);
-
- mTentativeUserSetResponse = savedInstanceState.getInt(
- BUNDLE_KEY_TENTATIVE_USER_RESPONSE,
- Attendees.ATTENDEE_STATUS_NONE);
- if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE &&
- mEditResponseHelper != null) {
- // If the edit response helper dialog is open, we'll need to
- // know if either of the choices were selected.
- mEditResponseHelper.setWhichEvents(savedInstanceState.getInt(
- BUNDLE_KEY_RESPONSE_WHICH_EVENTS, -1));
- }
- mUserSetResponse = savedInstanceState.getInt(
- BUNDLE_KEY_USER_SET_ATTENDEE_RESPONSE,
- Attendees.ATTENDEE_STATUS_NONE);
- if (mUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
- // If the response was set by the user before a configuration
- // change, we'll need to know which choice was selected.
- mWhichEvents = savedInstanceState.getInt(
- BUNDLE_KEY_RESPONSE_WHICH_EVENTS, -1);
- }
-
- mReminders = Utils.readRemindersFromBundle(savedInstanceState);
- }
-
if (mWindowStyle == DIALOG_WINDOW_STYLE) {
mView = inflater.inflate(R.layout.event_info_dialog, container, false);
} else {
@@ -909,20 +470,10 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
mTitle = (TextView) mView.findViewById(R.id.title);
mWhenDateTime = (TextView) mView.findViewById(R.id.when_datetime);
mWhere = (TextView) mView.findViewById(R.id.where);
- mDesc = (ExpandableTextView) mView.findViewById(R.id.description);
mHeadlines = mView.findViewById(R.id.event_info_headline);
- mLongAttendees = (AttendeesView) mView.findViewById(R.id.long_attendee_list);
mResponseRadioGroup = (RadioGroup) mView.findViewById(R.id.response_value);
- if (mUri == null) {
- // restore event ID from bundle
- mEventId = savedInstanceState.getLong(BUNDLE_KEY_EVENT_ID);
- mUri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId);
- mStartMillis = savedInstanceState.getLong(BUNDLE_KEY_START_MILLIS);
- mEndMillis = savedInstanceState.getLong(BUNDLE_KEY_END_MILLIS);
- }
-
mAnimateAlpha = ObjectAnimator.ofFloat(mScrollView, "Alpha", 0, 1);
mAnimateAlpha.setDuration(FADE_IN_TIME);
mAnimateAlpha.addListener(new AnimatorListenerAdapter() {
@@ -957,96 +508,17 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
mErrorMsgView.setVisibility(View.INVISIBLE);
mLoadingMsgView.postDelayed(mLoadingMsgAlphaUpdater, LOADING_MSG_DELAY);
- // start loading the data
-
- mHandler.startQuery(TOKEN_QUERY_EVENT, null, mUri, EVENT_PROJECTION,
- null, null, null);
-
- View b = mView.findViewById(R.id.delete);
- b.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (!mCanModifyCalendar) {
- return;
- }
- mDeleteHelper =
- new DeleteEventHelper(mContext, mActivity, !mIsDialog && !mIsTabletConfig /* exitWhenDone */);
- mDeleteHelper.setDeleteNotificationListener(EventInfoFragment.this);
- mDeleteHelper.setOnDismissListener(createDeleteOnDismissListener());
- mDeleteDialogVisible = true;
- mDeleteHelper.delete(mStartMillis, mEndMillis, mEventId, -1, onDeleteRunnable);
- }
- });
-
- b = mView.findViewById(R.id.change_color);
- b.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (!mCanModifyCalendar) {
- return;
- }
- showEventColorPickerDialog();
- }
- });
-
// Hide Edit/Delete buttons if in full screen mode on a phone
if (!mIsDialog && !mIsTabletConfig || mWindowStyle == EventInfoFragment.FULL_WINDOW_STYLE) {
mView.findViewById(R.id.event_info_buttons_container).setVisibility(View.GONE);
}
- // Create a listener for the email guests button
- emailAttendeesButton = (Button) mView.findViewById(R.id.email_attendees_button);
- if (emailAttendeesButton != null) {
- emailAttendeesButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- emailAttendees();
- }
- });
- }
-
- // Create a listener for the add reminder button
- View reminderAddButton = mView.findViewById(R.id.reminder_add);
- View.OnClickListener addReminderOnClickListener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- addReminder();
- mUserModifiedReminders = true;
- }
- };
- reminderAddButton.setOnClickListener(addReminderOnClickListener);
-
- // Set reminders variables
-
- SharedPreferences prefs = GeneralPreferences.getSharedPreferences(mActivity);
- String defaultReminderString = prefs.getString(
- GeneralPreferences.KEY_DEFAULT_REMINDER, GeneralPreferences.NO_REMINDER_STRING);
- mDefaultReminderMinutes = Integer.parseInt(defaultReminderString);
- prepareReminders();
-
return mView;
}
- private final Runnable onDeleteRunnable = new Runnable() {
- @Override
- public void run() {
- if (EventInfoFragment.this.mIsPaused) {
- mDismissOnResume = true;
- return;
- }
- if (EventInfoFragment.this.isVisible()) {
- EventInfoFragment.this.dismiss();
- }
- }
- };
-
private void updateTitle() {
Resources res = getActivity().getResources();
- if (mCanModifyCalendar && !mIsOrganizer) {
- getActivity().setTitle(res.getString(R.string.event_info_title_invite));
- } else {
- getActivity().setTitle(res.getString(R.string.event_info_title));
- }
+ getActivity().setTitle(res.getString(R.string.event_info_title));
}
/**
@@ -1061,148 +533,14 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
mEventCursor.moveToFirst();
mEventId = mEventCursor.getInt(EVENT_INDEX_ID);
String rRule = mEventCursor.getString(EVENT_INDEX_RRULE);
- mIsRepeating = !TextUtils.isEmpty(rRule);
- // mHasAlarm will be true if it was saved in the event already, or if
- // we've explicitly been provided reminders (e.g. during rotation).
- mHasAlarm = (mEventCursor.getInt(EVENT_INDEX_HAS_ALARM) == 1)? true :
- (mReminders != null && mReminders.size() > 0);
- mMaxReminders = mEventCursor.getInt(EVENT_INDEX_MAX_REMINDERS);
- mCalendarAllowedReminders = mEventCursor.getString(EVENT_INDEX_ALLOWED_REMINDERS);
+ // mHasAlarm will be true if it was saved in the event already.
+ mHasAlarm = (mEventCursor.getInt(EVENT_INDEX_HAS_ALARM) == 1)? true : false;
return true;
}
- @SuppressWarnings("fallthrough")
- private void initAttendeesCursor(View view) {
- mOriginalAttendeeResponse = Attendees.ATTENDEE_STATUS_NONE;
- mCalendarOwnerAttendeeId = EditEventHelper.ATTENDEE_ID_NONE;
- mNumOfAttendees = 0;
- if (mAttendeesCursor != null) {
- mNumOfAttendees = mAttendeesCursor.getCount();
- if (mAttendeesCursor.moveToFirst()) {
- mAcceptedAttendees.clear();
- mDeclinedAttendees.clear();
- mTentativeAttendees.clear();
- mNoResponseAttendees.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 (!TextUtils.isEmpty(name)) {
- mEventOrganizerDisplayName = name;
- if (!mIsOrganizer) {
- setVisibilityCommon(view, R.id.organizer_container, View.VISIBLE);
- setTextCommon(view, R.id.organizer, mEventOrganizerDisplayName);
- }
- }
- }
-
- if (mCalendarOwnerAttendeeId == EditEventHelper.ATTENDEE_ID_NONE &&
- mCalendarOwnerAccount.equalsIgnoreCase(email)) {
- mCalendarOwnerAttendeeId = mAttendeesCursor.getInt(ATTENDEES_INDEX_ID);
- mOriginalAttendeeResponse = mAttendeesCursor.getInt(ATTENDEES_INDEX_STATUS);
- } else {
- String identity = null;
- String idNamespace = null;
-
- if (Utils.isJellybeanOrLater()) {
- identity = mAttendeesCursor.getString(ATTENDEES_INDEX_IDENTITY);
- idNamespace = mAttendeesCursor.getString(ATTENDEES_INDEX_ID_NAMESPACE);
- }
-
- // 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,
- Attendees.ATTENDEE_STATUS_ACCEPTED, identity,
- idNamespace));
- break;
- case Attendees.ATTENDEE_STATUS_DECLINED:
- mDeclinedAttendees.add(new Attendee(name, email,
- Attendees.ATTENDEE_STATUS_DECLINED, identity,
- idNamespace));
- break;
- case Attendees.ATTENDEE_STATUS_TENTATIVE:
- mTentativeAttendees.add(new Attendee(name, email,
- Attendees.ATTENDEE_STATUS_TENTATIVE, identity,
- idNamespace));
- break;
- default:
- mNoResponseAttendees.add(new Attendee(name, email,
- Attendees.ATTENDEE_STATUS_NONE, identity,
- idNamespace));
- }
- }
- } while (mAttendeesCursor.moveToNext());
- mAttendeesCursor.moveToFirst();
-
- updateAttendees(view);
- }
- }
- }
-
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putLong(BUNDLE_KEY_EVENT_ID, mEventId);
- outState.putLong(BUNDLE_KEY_START_MILLIS, mStartMillis);
- outState.putLong(BUNDLE_KEY_END_MILLIS, mEndMillis);
- outState.putBoolean(BUNDLE_KEY_IS_DIALOG, mIsDialog);
- outState.putInt(BUNDLE_KEY_WINDOW_STYLE, mWindowStyle);
- outState.putBoolean(BUNDLE_KEY_DELETE_DIALOG_VISIBLE, mDeleteDialogVisible);
- outState.putInt(BUNDLE_KEY_CALENDAR_COLOR, mCalendarColor);
- outState.putBoolean(BUNDLE_KEY_CALENDAR_COLOR_INIT, mCalendarColorInitialized);
- outState.putInt(BUNDLE_KEY_ORIGINAL_COLOR, mOriginalColor);
- outState.putBoolean(BUNDLE_KEY_ORIGINAL_COLOR_INIT, mOriginalColorInitialized);
- outState.putInt(BUNDLE_KEY_CURRENT_COLOR, mCurrentColor);
- outState.putBoolean(BUNDLE_KEY_CURRENT_COLOR_INIT, mCurrentColorInitialized);
- outState.putInt(BUNDLE_KEY_CURRENT_COLOR_KEY, mCurrentColorKey);
-
- // We'll need the temporary response for configuration changes.
- outState.putInt(BUNDLE_KEY_TENTATIVE_USER_RESPONSE, mTentativeUserSetResponse);
- if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE &&
- mEditResponseHelper != null) {
- outState.putInt(BUNDLE_KEY_RESPONSE_WHICH_EVENTS,
- mEditResponseHelper.getWhichEvents());
- }
-
- // Save the current response.
- int response;
- if (mAttendeeResponseFromIntent != Attendees.ATTENDEE_STATUS_NONE) {
- response = mAttendeeResponseFromIntent;
- } else {
- response = mOriginalAttendeeResponse;
- }
- outState.putInt(BUNDLE_KEY_ATTENDEE_RESPONSE, response);
- if (mUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
- response = mUserSetResponse;
- outState.putInt(BUNDLE_KEY_USER_SET_ATTENDEE_RESPONSE, response);
- outState.putInt(BUNDLE_KEY_RESPONSE_WHICH_EVENTS, mWhichEvents);
- }
-
- // Save the reminders.
- mReminders = EventViewUtils.reminderItemsToReminders(mReminderViews,
- mReminderMinuteValues, mReminderMethodValues);
- int numReminders = mReminders.size();
- ArrayList<Integer> reminderMinutes =
- new ArrayList<Integer>(numReminders);
- ArrayList<Integer> reminderMethods =
- new ArrayList<Integer>(numReminders);
- for (ReminderEntry reminder : mReminders) {
- reminderMinutes.add(reminder.getMinutes());
- reminderMethods.add(reminder.getMethod());
- }
- outState.putIntegerArrayList(
- BUNDLE_KEY_REMINDER_MINUTES, reminderMinutes);
- outState.putIntegerArrayList(
- BUNDLE_KEY_REMINDER_METHODS, reminderMethods);
}
@Override
@@ -1212,7 +550,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
if (!mIsDialog && !mIsTabletConfig || mWindowStyle == EventInfoFragment.FULL_WINDOW_STYLE) {
inflater.inflate(R.menu.event_info_title_bar, menu);
mMenu = menu;
- updateMenu();
}
}
@@ -1237,62 +574,13 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
mActivity.finish();
return true;
} else if (itemId == R.id.info_action_edit) {
- doEdit();
mActivity.finish();
- } else if (itemId == R.id.info_action_delete) {
- mDeleteHelper =
- new DeleteEventHelper(mActivity, mActivity, true /* exitWhenDone */);
- mDeleteHelper.setDeleteNotificationListener(EventInfoFragment.this);
- mDeleteHelper.setOnDismissListener(createDeleteOnDismissListener());
- mDeleteDialogVisible = true;
- mDeleteHelper.delete(mStartMillis, mEndMillis, mEventId, -1, onDeleteRunnable);
- } else if (itemId == R.id.info_action_change_color) {
- showEventColorPickerDialog();
}
return super.onOptionsItemSelected(item);
}
- private void showEventColorPickerDialog() {
- if (mColorPickerDialog == null) {
- mColorPickerDialog = EventColorPickerDialog.newInstance(mColors, mCurrentColor,
- mCalendarColor, mIsTabletConfig);
- mColorPickerDialog.setOnColorSelectedListener(this);
- }
- final FragmentManager fragmentManager = getFragmentManager();
- fragmentManager.executePendingTransactions();
- if (!mColorPickerDialog.isAdded()) {
- mColorPickerDialog.show(fragmentManager, COLOR_PICKER_DIALOG_TAG);
- }
- }
-
- private boolean saveEventColor() {
- if (mCurrentColor == mOriginalColor) {
- return false;
- }
-
- ContentValues values = new ContentValues();
- if (mCurrentColor != mCalendarColor) {
- values.put(Events.EVENT_COLOR_KEY, mCurrentColorKey);
- } else {
- values.put(Events.EVENT_COLOR_KEY, NO_EVENT_COLOR);
- }
- Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId);
- mHandler.startUpdate(mHandler.getNextToken(), null, uri, values,
- null, null, Utils.UNDO_DELAY);
- return true;
- }
-
@Override
public void onStop() {
- Activity act = getActivity();
- if (!mEventDeletionStarted && act != null && !act.isChangingConfigurations()) {
-
- boolean responseSaved = saveResponse();
- boolean eventColorSaved = saveEventColor();
- if (saveReminders() || responseSaved || eventColorSaved) {
- Toast.makeText(getActivity(), R.string.saving_event, Toast.LENGTH_SHORT).show();
- }
- }
super.onStop();
}
@@ -1304,86 +592,10 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
if (mCalendarsCursor != null) {
mCalendarsCursor.close();
}
- if (mAttendeesCursor != null) {
- mAttendeesCursor.close();
- }
super.onDestroy();
}
/**
- * Asynchronously saves the response to an invitation if the user changed
- * the response. Returns true if the database will be updated.
- *
- * @return true if the database will be changed
- */
- private boolean saveResponse() {
- if (mAttendeesCursor == null || mEventCursor == null) {
- return false;
- }
-
- int status = getResponseFromButtonId(
- mResponseRadioGroup.getCheckedRadioButtonId());
- if (status == Attendees.ATTENDEE_STATUS_NONE) {
- return false;
- }
-
- // If the status has not changed, then don't update the database
- if (status == mOriginalAttendeeResponse) {
- return false;
- }
-
- // If we never got an owner attendee id we can't set the status
- if (mCalendarOwnerAttendeeId == EditEventHelper.ATTENDEE_ID_NONE) {
- return false;
- }
-
- if (!mIsRepeating) {
- // This is a non-repeating event
- updateResponse(mEventId, mCalendarOwnerAttendeeId, status);
- mOriginalAttendeeResponse = status;
- return true;
- }
-
- if (DEBUG) {
- Log.d(TAG, "Repeating event: mWhichEvents=" + mWhichEvents);
- }
- // This is a repeating event
- switch (mWhichEvents) {
- case -1:
- return false;
- case UPDATE_SINGLE:
- createExceptionResponse(mEventId, status);
- mOriginalAttendeeResponse = status;
- return true;
- case UPDATE_ALL:
- updateResponse(mEventId, mCalendarOwnerAttendeeId, status);
- mOriginalAttendeeResponse = status;
- return true;
- default:
- Log.e(TAG, "Unexpected choice for updating invitation response");
- break;
- }
- return false;
- }
-
- private void updateResponse(long eventId, long attendeeId, int status) {
- // Update the attendee status in the attendees table. the provider
- // takes care of updating the self attendance status.
- ContentValues values = new ContentValues();
-
- 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);
-
- mHandler.startUpdate(mHandler.getNextToken(), null, uri, values,
- null, null, Utils.UNDO_DELAY);
- }
-
- /**
* Creates an exception to a recurring event. The only change we're making is to the
* "self attendee status" value. The provider will take care of updating the corresponding
* Attendees.attendeeStatus entry.
@@ -1401,61 +613,14 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
Uri exceptionUri = Uri.withAppendedPath(Events.CONTENT_EXCEPTION_URI,
String.valueOf(eventId));
ops.add(ContentProviderOperation.newInsert(exceptionUri).withValues(values).build());
-
- mHandler.startBatch(mHandler.getNextToken(), null, CalendarContract.AUTHORITY, ops,
- Utils.UNDO_DELAY);
}
public static int getResponseFromButtonId(int buttonId) {
- int response;
- if (buttonId == R.id.response_yes) {
- response = Attendees.ATTENDEE_STATUS_ACCEPTED;
- } else if (buttonId == R.id.response_maybe) {
- response = Attendees.ATTENDEE_STATUS_TENTATIVE;
- } else if (buttonId == R.id.response_no) {
- response = Attendees.ATTENDEE_STATUS_DECLINED;
- } else {
- response = Attendees.ATTENDEE_STATUS_NONE;
- }
- return response;
+ return Attendees.ATTENDEE_STATUS_NONE;
}
public static int findButtonIdForResponse(int response) {
- int buttonId;
- switch (response) {
- case Attendees.ATTENDEE_STATUS_ACCEPTED:
- buttonId = R.id.response_yes;
- break;
- case Attendees.ATTENDEE_STATUS_TENTATIVE:
- buttonId = R.id.response_maybe;
- break;
- case Attendees.ATTENDEE_STATUS_DECLINED:
- buttonId = R.id.response_no;
- break;
- default:
- buttonId = -1;
- }
- return buttonId;
- }
-
- private void doEdit() {
- Context c = getActivity();
- // This ensures that we aren't in the process of closing and have been
- // unattached already
- if (c != null) {
- Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId);
- Intent intent = new Intent(Intent.ACTION_EDIT, uri);
- intent.setClass(mActivity, EditEventActivity.class);
- intent.putExtra(EXTRA_EVENT_BEGIN_TIME, mStartMillis);
- intent.putExtra(EXTRA_EVENT_END_TIME, mEndMillis);
- intent.putExtra(EXTRA_EVENT_ALL_DAY, mAllDay);
- intent.putExtra(EditEventActivity.EXTRA_EVENT_COLOR, mCurrentColor);
- intent.putExtra(EditEventActivity.EXTRA_EVENT_REMINDERS, EventViewUtils
- .reminderItemsToReminders(mReminderViews, mReminderMinuteValues,
- mReminderMethodValues));
- intent.putExtra(EVENT_EDIT_ON_LAUNCH, true);
- startActivity(intent);
- }
+ return -1;
}
private void displayEventNotFound() {
@@ -1546,25 +711,7 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
setTextCommon(view, R.id.when_datetime, sb);
}
- // Display the repeat string (if any)
- String repeatString = null;
- if (!TextUtils.isEmpty(rRule)) {
- EventRecurrence eventRecurrence = new EventRecurrence();
- eventRecurrence.parse(rRule);
- Time date = new Time(localTimezone);
- date.set(mStartMillis);
- if (mAllDay) {
- date.timezone = Time.TIMEZONE_UTC;
- }
- eventRecurrence.setStartDate(date);
- repeatString = EventRecurrenceFormatter.getRepeatString(mContext, resources,
- eventRecurrence, true);
- }
- if (repeatString == null) {
- view.findViewById(R.id.when_repeat).setVisibility(View.GONE);
- } else {
- setTextCommon(view, R.id.when_repeat, repeatString);
- }
+ view.findViewById(R.id.when_repeat).setVisibility(View.GONE);
// Organizer view is setup in the updateCalendar method
@@ -1575,44 +722,10 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
} else {
final TextView textView = mWhere;
if (textView != null) {
- textView.setAutoLinkMask(0);
textView.setText(location.trim());
- try {
- textView.setText(Utils.extendedLinkify(textView.getText().toString(), true));
-
- // Linkify.addLinks() sets the TextView movement method if it finds any links.
- // We must do the same here, in case linkify by itself did not find any.
- // (This is cloned from Linkify.addLinkMovementMethod().)
- MovementMethod mm = textView.getMovementMethod();
- if ((mm == null) || !(mm instanceof LinkMovementMethod)) {
- if (textView.getLinksClickable()) {
- textView.setMovementMethod(LinkMovementMethod.getInstance());
- }
- }
- } catch (Exception ex) {
- // unexpected
- Log.e(TAG, "Linkification failed", ex);
- }
-
- textView.setOnTouchListener(new OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- try {
- return v.onTouchEvent(event);
- } catch (ActivityNotFoundException e) {
- // ignore
- return true;
- }
- }
- });
}
}
- // Description
- if (description != null && description.length() != 0) {
- mDesc.setText(description);
- }
-
// Launch Custom App
if (Utils.isJellybeanOrLater()) {
updateCustomAppButton();
@@ -1620,74 +733,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
}
private void updateCustomAppButton() {
- buttonSetup: {
- final Button launchButton = (Button) mView.findViewById(R.id.launch_custom_app_button);
- if (launchButton == null)
- break buttonSetup;
-
- final String customAppPackage = mEventCursor.getString(EVENT_INDEX_CUSTOM_APP_PACKAGE);
- final String customAppUri = mEventCursor.getString(EVENT_INDEX_CUSTOM_APP_URI);
-
- if (TextUtils.isEmpty(customAppPackage) || TextUtils.isEmpty(customAppUri))
- break buttonSetup;
-
- PackageManager pm = mContext.getPackageManager();
- if (pm == null)
- break buttonSetup;
-
- ApplicationInfo info;
- try {
- info = pm.getApplicationInfo(customAppPackage, 0);
- if (info == null)
- break buttonSetup;
- } catch (NameNotFoundException e) {
- break buttonSetup;
- }
-
- Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId);
- final Intent intent = new Intent(CalendarContract.ACTION_HANDLE_CUSTOM_EVENT, uri);
- intent.setPackage(customAppPackage);
- intent.putExtra(CalendarContract.EXTRA_CUSTOM_APP_URI, customAppUri);
- intent.putExtra(EXTRA_EVENT_BEGIN_TIME, mStartMillis);
-
- // See if we have a taker for our intent
- if (pm.resolveActivity(intent, 0) == null)
- break buttonSetup;
-
- Drawable icon = pm.getApplicationIcon(info);
- if (icon != null) {
-
- Drawable[] d = launchButton.getCompoundDrawables();
- icon.setBounds(0, 0, mCustomAppIconSize, mCustomAppIconSize);
- launchButton.setCompoundDrawables(icon, d[1], d[2], d[3]);
- }
-
- CharSequence label = pm.getApplicationLabel(info);
- if (label != null && label.length() != 0) {
- launchButton.setText(label);
- } else if (icon == null) {
- // No icon && no label. Hide button?
- break buttonSetup;
- }
-
- // Launch custom app
- launchButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- try {
- startActivityForResult(intent, 0);
- } catch (ActivityNotFoundException e) {
- // Shouldn't happen as we checked it already
- setVisibilityCommon(mView, R.id.launch_custom_app_container, View.GONE);
- }
- }
- });
-
- setVisibilityCommon(mView, R.id.launch_custom_app_container, View.VISIBLE);
- return;
-
- }
-
setVisibilityCommon(mView, R.id.launch_custom_app_container, View.GONE);
return;
}
@@ -1704,11 +749,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
event.setPackageName(getActivity().getPackageName());
List<CharSequence> text = event.getText();
- addFieldToAccessibilityEvent(text, mTitle, null);
- addFieldToAccessibilityEvent(text, mWhenDateTime, null);
- addFieldToAccessibilityEvent(text, mWhere, null);
- addFieldToAccessibilityEvent(text, null, mDesc);
-
if (mResponseRadioGroup.getVisibility() == View.VISIBLE) {
int id = mResponseRadioGroup.getCheckedRadioButtonId();
if (id != View.NO_ID) {
@@ -1721,26 +761,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
am.sendAccessibilityEvent(event);
}
- private void addFieldToAccessibilityEvent(List<CharSequence> text, TextView tv,
- ExpandableTextView etv) {
- CharSequence cs;
- if (tv != null) {
- cs = tv.getText();
- } else if (etv != null) {
- cs = etv.getText();
- } else {
- return;
- }
-
- if (!TextUtils.isEmpty(cs)) {
- cs = cs.toString().trim();
- if (cs.length() > 0) {
- text.add(cs);
- text.add(PERIOD_SPACE);
- }
- }
- }
-
private void updateCalendar(View view) {
mCalendarOwnerAccount = "";
@@ -1751,29 +771,7 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
mOwnerCanRespond = mCalendarsCursor.getInt(CALENDARS_INDEX_OWNER_CAN_RESPOND) != 0;
mSyncAccountName = mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_NAME);
- // start visible calendars query
- mHandler.startQuery(TOKEN_QUERY_VISIBLE_CALENDARS, null, Calendars.CONTENT_URI,
- CALENDARS_PROJECTION, CALENDARS_VISIBLE_WHERE, new String[] {"1"}, null);
-
- mEventOrganizerEmail = mEventCursor.getString(EVENT_INDEX_ORGANIZER);
- mIsOrganizer = mCalendarOwnerAccount.equalsIgnoreCase(mEventOrganizerEmail);
-
- if (!TextUtils.isEmpty(mEventOrganizerEmail) &&
- !mEventOrganizerEmail.endsWith(Utils.MACHINE_GENERATED_ADDRESS)) {
- mEventOrganizerDisplayName = mEventOrganizerEmail;
- }
-
- if (!mIsOrganizer && !TextUtils.isEmpty(mEventOrganizerDisplayName)) {
- setTextCommon(view, R.id.organizer, mEventOrganizerDisplayName);
- setVisibilityCommon(view, R.id.organizer_container, View.VISIBLE);
- } else {
- setVisibilityCommon(view, R.id.organizer_container, View.GONE);
- }
- mHasAttendeeData = mEventCursor.getInt(EVENT_INDEX_HAS_ATTENDEE_DATA) != 0;
- mCanModifyCalendar = mEventCursor.getInt(EVENT_INDEX_ACCESS_LEVEL)
- >= Calendars.CAL_ACCESS_CONTRIBUTOR;
- // TODO add "|| guestCanModify" after b/1299071 is fixed
- mCanModifyEvent = mCanModifyCalendar && mIsOrganizer;
+ setVisibilityCommon(view, R.id.organizer_container, View.GONE);
mIsBusyFreeCalendar =
mEventCursor.getInt(EVENT_INDEX_ACCESS_LEVEL) == Calendars.CAL_ACCESS_FREEBUSY;
@@ -1784,7 +782,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- doEdit();
// For dialogs, just close the fragment
// For full screen, close activity on phone, leave it for tablet
if (mIsDialog) {
@@ -1797,20 +794,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
});
}
View button;
- if (mCanModifyCalendar) {
- button = mView.findViewById(R.id.delete);
- if (button != null) {
- button.setEnabled(true);
- button.setVisibility(View.VISIBLE);
- }
- }
- if (mCanModifyEvent) {
- button = mView.findViewById(R.id.edit);
- if (button != null) {
- button.setEnabled(true);
- button.setVisibility(View.VISIBLE);
- }
- }
if ((!mIsDialog && !mIsTabletConfig ||
mWindowStyle == EventInfoFragment.FULL_WINDOW_STYLE) && mMenu != null) {
mActivity.invalidateOptionsMenu();
@@ -1821,190 +804,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
}
}
- /**
- *
- */
- private void updateMenu() {
- if (mMenu == null) {
- return;
- }
- MenuItem delete = mMenu.findItem(R.id.info_action_delete);
- MenuItem edit = mMenu.findItem(R.id.info_action_edit);
- MenuItem changeColor = mMenu.findItem(R.id.info_action_change_color);
- if (delete != null) {
- delete.setVisible(mCanModifyCalendar);
- delete.setEnabled(mCanModifyCalendar);
- }
- if (edit != null) {
- edit.setVisible(mCanModifyEvent);
- edit.setEnabled(mCanModifyEvent);
- }
- if (changeColor != null && mColors != null && mColors.length > 0) {
- changeColor.setVisible(mCanModifyCalendar);
- changeColor.setEnabled(mCanModifyCalendar);
- }
- }
-
- private void updateAttendees(View view) {
- if (mAcceptedAttendees.size() + mDeclinedAttendees.size() +
- mTentativeAttendees.size() + mNoResponseAttendees.size() > 0) {
- mLongAttendees.clearAttendees();
- (mLongAttendees).addAttendees(mAcceptedAttendees);
- (mLongAttendees).addAttendees(mDeclinedAttendees);
- (mLongAttendees).addAttendees(mTentativeAttendees);
- (mLongAttendees).addAttendees(mNoResponseAttendees);
- mLongAttendees.setEnabled(false);
- mLongAttendees.setVisibility(View.VISIBLE);
- } else {
- mLongAttendees.setVisibility(View.GONE);
- }
-
- if (hasEmailableAttendees()) {
- setVisibilityCommon(mView, R.id.email_attendees_container, View.VISIBLE);
- if (emailAttendeesButton != null) {
- emailAttendeesButton.setText(R.string.email_guests_label);
- }
- } else if (hasEmailableOrganizer()) {
- setVisibilityCommon(mView, R.id.email_attendees_container, View.VISIBLE);
- if (emailAttendeesButton != null) {
- emailAttendeesButton.setText(R.string.email_organizer_label);
- }
- } else {
- setVisibilityCommon(mView, R.id.email_attendees_container, View.GONE);
- }
- }
-
- /**
- * Returns true if there is at least 1 attendee that is not the viewer.
- */
- private boolean hasEmailableAttendees() {
- for (Attendee attendee : mAcceptedAttendees) {
- if (Utils.isEmailableFrom(attendee.mEmail, mSyncAccountName)) {
- return true;
- }
- }
- for (Attendee attendee : mTentativeAttendees) {
- if (Utils.isEmailableFrom(attendee.mEmail, mSyncAccountName)) {
- return true;
- }
- }
- for (Attendee attendee : mNoResponseAttendees) {
- if (Utils.isEmailableFrom(attendee.mEmail, mSyncAccountName)) {
- return true;
- }
- }
- for (Attendee attendee : mDeclinedAttendees) {
- if (Utils.isEmailableFrom(attendee.mEmail, mSyncAccountName)) {
- return true;
- }
- }
- return false;
- }
-
- private boolean hasEmailableOrganizer() {
- return mEventOrganizerEmail != null &&
- Utils.isEmailableFrom(mEventOrganizerEmail, mSyncAccountName);
- }
-
- public void initReminders(View view, Cursor cursor) {
-
- // Add reminders
- mOriginalReminders.clear();
- mUnsupportedReminders.clear();
- while (cursor.moveToNext()) {
- int minutes = cursor.getInt(EditEventHelper.REMINDERS_INDEX_MINUTES);
- int method = cursor.getInt(EditEventHelper.REMINDERS_INDEX_METHOD);
-
- if (method != Reminders.METHOD_DEFAULT && !mReminderMethodValues.contains(method)) {
- // Stash unsupported reminder types separately so we don't alter
- // them in the UI
- mUnsupportedReminders.add(ReminderEntry.valueOf(minutes, method));
- } else {
- mOriginalReminders.add(ReminderEntry.valueOf(minutes, method));
- }
- }
- // Sort appropriately for display (by time, then type)
- Collections.sort(mOriginalReminders);
-
- if (mUserModifiedReminders) {
- // If the user has changed the list of reminders don't change what's
- // shown.
- return;
- }
-
- LinearLayout parent = (LinearLayout) mScrollView
- .findViewById(R.id.reminder_items_container);
- if (parent != null) {
- parent.removeAllViews();
- }
- if (mReminderViews != null) {
- mReminderViews.clear();
- }
-
- if (mHasAlarm) {
- ArrayList<ReminderEntry> reminders;
- // If applicable, use reminders saved in the bundle.
- if (mReminders != null) {
- reminders = mReminders;
- } else {
- reminders = mOriginalReminders;
- }
- // Insert any minute values that aren't represented in the minutes list.
- for (ReminderEntry re : reminders) {
- EventViewUtils.addMinutesToList(
- mActivity, mReminderMinuteValues, mReminderMinuteLabels, re.getMinutes());
- }
- // Create a UI element for each reminder. We display all of the reminders we get
- // from the provider, even if the count exceeds the calendar maximum. (Also, for
- // a new event, we won't have a maxReminders value available.)
- for (ReminderEntry re : reminders) {
- EventViewUtils.addReminder(mActivity, mScrollView, this, mReminderViews,
- mReminderMinuteValues, mReminderMinuteLabels, mReminderMethodValues,
- mReminderMethodLabels, re, Integer.MAX_VALUE, mReminderChangeListener);
- }
- EventViewUtils.updateAddReminderButton(mView, mReminderViews, mMaxReminders);
- // TODO show unsupported reminder types in some fashion.
- }
- }
-
- void updateResponse(View view) {
- // 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 AND
- // c) organizerCanRespond is enabled for the calendar
- // (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).
-
- // TODO Switch to EditEventHelper.canRespond when this class uses CalendarEventModel.
- if (!mCanModifyCalendar || (mHasAttendeeData && mIsOrganizer && mNumOfAttendees <= 1) ||
- (mIsOrganizer && !mOwnerCanRespond)) {
- setVisibilityCommon(view, R.id.response_container, View.GONE);
- return;
- }
-
- setVisibilityCommon(view, R.id.response_container, View.VISIBLE);
-
-
- int response;
- if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
- response = mTentativeUserSetResponse;
- } else if (mUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
- response = mUserSetResponse;
- } else if (mAttendeeResponseFromIntent != Attendees.ATTENDEE_STATUS_NONE) {
- response = mAttendeeResponseFromIntent;
- } else {
- response = mOriginalAttendeeResponse;
- }
-
- int buttonToCheck = findButtonIdForResponse(response);
- mResponseRadioGroup.check(buttonToCheck); // -1 clear all radio buttons
- mResponseRadioGroup.setOnCheckedChangeListener(this);
- }
-
private void setTextCommon(View view, int id, CharSequence text) {
TextView textView = (TextView) view.findViewById(id);
if (textView == null)
@@ -2020,58 +819,10 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
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 = getActivity().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(getActivity(), 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);
- }
- }
-
@Override
public void onPause() {
mIsPaused = true;
- mHandler.removeCallbacks(onDeleteRunnable);
super.onPause();
- // Remove event deletion alert box since it is being rebuild in the OnResume
- // This is done to get the same behavior on OnResume since the AlertDialog is gone on
- // rotation but not if you press the HOME key
- if (mDeleteDialogVisible && mDeleteHelper != null) {
- mDeleteHelper.dismissAlertDialog();
- mDeleteHelper = null;
- }
- if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE
- && mEditResponseHelper != null) {
- mEditResponseHelper.dismissAlertDialog();
- }
}
@Override
@@ -2082,20 +833,9 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
applyDialogParams();
}
mIsPaused = false;
- if (mDismissOnResume) {
- mHandler.post(onDeleteRunnable);
- }
- // Display the "delete confirmation" or "edit response helper" dialog if needed
- if (mDeleteDialogVisible) {
- mDeleteHelper = new DeleteEventHelper(
- mContext, mActivity,
- !mIsDialog && !mIsTabletConfig /* exitWhenDone */);
- mDeleteHelper.setOnDismissListener(createDeleteOnDismissListener());
- mDeleteHelper.delete(mStartMillis, mEndMillis, mEventId, -1, onDeleteRunnable);
- } else if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
+ if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
int buttonId = findButtonIdForResponse(mTentativeUserSetResponse);
mResponseRadioGroup.check(buttonId);
- mEditResponseHelper.showDialog(mEditResponseHelper.getWhichEvents());
}
}
@@ -2114,164 +854,10 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
}
public void reloadEvents() {
- if (mHandler != null) {
- mHandler.startQuery(TOKEN_QUERY_EVENT, null, mUri, EVENT_PROJECTION,
- null, null, null);
- }
}
@Override
public void onClick(View view) {
-
- // This must be a click on one of the "remove reminder" buttons
- LinearLayout reminderItem = (LinearLayout) view.getParent();
- LinearLayout parent = (LinearLayout) reminderItem.getParent();
- parent.removeView(reminderItem);
- mReminderViews.remove(reminderItem);
- mUserModifiedReminders = true;
- EventViewUtils.updateAddReminderButton(mView, mReminderViews, mMaxReminders);
- }
-
-
- /**
- * Add a new reminder when the user hits the "add reminder" button. We use the default
- * reminder time and method.
- */
- private void addReminder() {
- // TODO: when adding a new reminder, make it different from the
- // last one in the list (if any).
- if (mDefaultReminderMinutes == GeneralPreferences.NO_REMINDER) {
- EventViewUtils.addReminder(mActivity, mScrollView, this, mReminderViews,
- mReminderMinuteValues, mReminderMinuteLabels, mReminderMethodValues,
- mReminderMethodLabels,
- ReminderEntry.valueOf(GeneralPreferences.REMINDER_DEFAULT_TIME), mMaxReminders,
- mReminderChangeListener);
- } else {
- EventViewUtils.addReminder(mActivity, mScrollView, this, mReminderViews,
- mReminderMinuteValues, mReminderMinuteLabels, mReminderMethodValues,
- mReminderMethodLabels, ReminderEntry.valueOf(mDefaultReminderMinutes),
- mMaxReminders, mReminderChangeListener);
- }
-
- EventViewUtils.updateAddReminderButton(mView, mReminderViews, mMaxReminders);
- }
-
- synchronized private void prepareReminders() {
- // Nothing to do if we've already built these lists _and_ we aren't
- // removing not allowed methods
- if (mReminderMinuteValues != null && mReminderMinuteLabels != null
- && mReminderMethodValues != null && mReminderMethodLabels != null
- && mCalendarAllowedReminders == null) {
- return;
- }
- // Load the labels and corresponding numeric values for the minutes and methods lists
- // from the assets. If we're switching calendars, we need to clear and re-populate the
- // lists (which may have elements added and removed based on calendar properties). This
- // is mostly relevant for "methods", since we shouldn't have any "minutes" values in a
- // new event that aren't in the default set.
- Resources r = mActivity.getResources();
- mReminderMinuteValues = loadIntegerArray(r, R.array.reminder_minutes_values);
- mReminderMinuteLabels = loadStringArray(r, R.array.reminder_minutes_labels);
- mReminderMethodValues = loadIntegerArray(r, R.array.reminder_methods_values);
- mReminderMethodLabels = loadStringArray(r, R.array.reminder_methods_labels);
-
- // Remove any reminder methods that aren't allowed for this calendar. If this is
- // a new event, mCalendarAllowedReminders may not be set the first time we're called.
- if (mCalendarAllowedReminders != null) {
- EventViewUtils.reduceMethodList(mReminderMethodValues, mReminderMethodLabels,
- mCalendarAllowedReminders);
- }
- if (mView != null) {
- mView.invalidate();
- }
- }
-
-
- private boolean saveReminders() {
- ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(3);
-
- // Read reminders from UI
- mReminders = EventViewUtils.reminderItemsToReminders(mReminderViews,
- mReminderMinuteValues, mReminderMethodValues);
- mOriginalReminders.addAll(mUnsupportedReminders);
- Collections.sort(mOriginalReminders);
- mReminders.addAll(mUnsupportedReminders);
- Collections.sort(mReminders);
-
- // Check if there are any changes in the reminder
- boolean changed = EditEventHelper.saveReminders(ops, mEventId, mReminders,
- mOriginalReminders, false /* no force save */);
-
- if (!changed) {
- return false;
- }
-
- // save new reminders
- AsyncQueryService service = new AsyncQueryService(getActivity());
- service.startBatch(0, null, Calendars.CONTENT_URI.getAuthority(), ops, 0);
- mOriginalReminders = mReminders;
- // Update the "hasAlarm" field for the event
- Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId);
- int len = mReminders.size();
- boolean hasAlarm = len > 0;
- if (hasAlarm != mHasAlarm) {
- ContentValues values = new ContentValues();
- values.put(Events.HAS_ALARM, hasAlarm ? 1 : 0);
- service.startUpdate(0, null, uri, values, null, null, 0);
- }
- return true;
- }
-
- /**
- * Email all the attendees of the event, except for the viewer (so as to not email
- * himself) and resources like conference rooms.
- */
- private void emailAttendees() {
- Intent i = new Intent(getActivity(), QuickResponseActivity.class);
- i.putExtra(QuickResponseActivity.EXTRA_EVENT_ID, mEventId);
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(i);
- }
-
- /**
- * Loads an integer array asset into a list.
- */
- private static ArrayList<Integer> loadIntegerArray(Resources r, int resNum) {
- int[] vals = r.getIntArray(resNum);
- int size = vals.length;
- ArrayList<Integer> list = new ArrayList<Integer>(size);
-
- for (int i = 0; i < size; i++) {
- list.add(vals[i]);
- }
-
- return list;
- }
- /**
- * Loads a String array asset into a list.
- */
- private static ArrayList<String> loadStringArray(Resources r, int resNum) {
- String[] labels = r.getStringArray(resNum);
- ArrayList<String> list = new ArrayList<String>(Arrays.asList(labels));
- return list;
- }
-
- @Override
- public void onDeleteStarted() {
- mEventDeletionStarted = true;
- }
-
- private Dialog.OnDismissListener createDeleteOnDismissListener() {
- return new Dialog.OnDismissListener() {
- @Override
- public void onDismiss(DialogInterface dialog) {
- // Since OnPause will force the dialog to dismiss , do
- // not change the dialog status
- if (!mIsPaused) {
- mDeleteDialogVisible = false;
- }
- }
- };
}
public long getEventId() {
@@ -2288,11 +874,4 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
mDialogWidth = (int)r.getDimension(R.dimen.event_info_dialog_width);
mDialogHeight = (int)r.getDimension(R.dimen.event_info_dialog_height);
}
-
- @Override
- public void onColorSelected(int color) {
- mCurrentColor = color;
- mCurrentColorKey = mDisplayColorKeyMap.get(color);
- mHeadlines.setBackgroundColor(color);
- }
}
diff --git a/src/com/android/calendar/EventRecurrenceFormatter.java b/src/com/android/calendar/EventRecurrenceFormatter.java
deleted file mode 100644
index b9e33fdd..00000000
--- a/src/com/android/calendar/EventRecurrenceFormatter.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2006 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.Context;
-import android.content.res.Resources;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-import android.util.TimeFormatException;
-
-import com.android.calendarcommon2.EventRecurrence;
-
-import java.util.Calendar;
-
-public class EventRecurrenceFormatter
-{
-
- private static int[] mMonthRepeatByDayOfWeekIds;
- private static String[][] mMonthRepeatByDayOfWeekStrs;
-
- public static String getRepeatString(Context context, Resources r, EventRecurrence recurrence,
- boolean includeEndString) {
- String endString = "";
- if (includeEndString) {
- StringBuilder sb = new StringBuilder();
- if (recurrence.until != null) {
- try {
- Time t = new Time();
- t.parse(recurrence.until);
- final String dateStr = DateUtils.formatDateTime(context,
- t.toMillis(false), DateUtils.FORMAT_NUMERIC_DATE);
- sb.append(r.getString(R.string.endByDate, dateStr));
- } catch (TimeFormatException e) {
- }
- }
-
- if (recurrence.count > 0) {
- sb.append(r.getQuantityString(R.plurals.endByCount, recurrence.count,
- recurrence.count));
- }
- endString = sb.toString();
- }
-
- // TODO Implement "Until" portion of string, as well as custom settings
- int interval = recurrence.interval <= 1 ? 1 : recurrence.interval;
- switch (recurrence.freq) {
- case EventRecurrence.DAILY:
- return r.getQuantityString(R.plurals.daily, interval, interval) + endString;
- case EventRecurrence.WEEKLY: {
- if (recurrence.repeatsOnEveryWeekDay()) {
- return r.getString(R.string.every_weekday) + endString;
- } else {
- String string;
-
- int dayOfWeekLength = DateUtils.LENGTH_MEDIUM;
- if (recurrence.bydayCount == 1) {
- dayOfWeekLength = DateUtils.LENGTH_LONG;
- }
-
- StringBuilder days = new StringBuilder();
-
- // Do one less iteration in the loop so the last element is added out of the
- // loop. This is done so the comma is not placed after the last item.
-
- if (recurrence.bydayCount > 0) {
- int count = recurrence.bydayCount - 1;
- for (int i = 0 ; i < count ; i++) {
- days.append(dayToString(recurrence.byday[i], dayOfWeekLength));
- days.append(", ");
- }
- days.append(dayToString(recurrence.byday[count], dayOfWeekLength));
-
- string = days.toString();
- } else {
- // There is no "BYDAY" specifier, so use the day of the
- // first event. For this to work, the setStartDate()
- // method must have been used by the caller to set the
- // date of the first event in the recurrence.
- if (recurrence.startDate == null) {
- return null;
- }
-
- int day = EventRecurrence.timeDay2Day(recurrence.startDate.weekDay);
- string = dayToString(day, DateUtils.LENGTH_LONG);
- }
- return r.getQuantityString(R.plurals.weekly, interval, interval, string)
- + endString;
- }
- }
- case EventRecurrence.MONTHLY: {
- if (recurrence.bydayCount == 1) {
- int weekday = recurrence.startDate.weekDay;
- // Cache this stuff so we won't have to redo work again later.
- cacheMonthRepeatStrings(r, weekday);
- int dayNumber = (recurrence.startDate.monthDay - 1) / 7;
- StringBuilder sb = new StringBuilder();
- sb.append(r.getString(R.string.monthly));
- sb.append(" (");
- sb.append(mMonthRepeatByDayOfWeekStrs[weekday][dayNumber]);
- sb.append(")");
- sb.append(endString);
- return sb.toString();
- }
- return r.getString(R.string.monthly) + endString;
- }
- case EventRecurrence.YEARLY:
- return r.getString(R.string.yearly_plain) + endString;
- }
-
- return null;
- }
-
- private static void cacheMonthRepeatStrings(Resources r, int weekday) {
- if (mMonthRepeatByDayOfWeekIds == null) {
- mMonthRepeatByDayOfWeekIds = new int[7];
- mMonthRepeatByDayOfWeekIds[0] = R.array.repeat_by_nth_sun;
- mMonthRepeatByDayOfWeekIds[1] = R.array.repeat_by_nth_mon;
- mMonthRepeatByDayOfWeekIds[2] = R.array.repeat_by_nth_tues;
- mMonthRepeatByDayOfWeekIds[3] = R.array.repeat_by_nth_wed;
- mMonthRepeatByDayOfWeekIds[4] = R.array.repeat_by_nth_thurs;
- mMonthRepeatByDayOfWeekIds[5] = R.array.repeat_by_nth_fri;
- mMonthRepeatByDayOfWeekIds[6] = R.array.repeat_by_nth_sat;
- }
- if (mMonthRepeatByDayOfWeekStrs == null) {
- mMonthRepeatByDayOfWeekStrs = new String[7][];
- }
- if (mMonthRepeatByDayOfWeekStrs[weekday] == null) {
- mMonthRepeatByDayOfWeekStrs[weekday] =
- r.getStringArray(mMonthRepeatByDayOfWeekIds[weekday]);
- }
- }
-
- /**
- * Converts day of week to a String.
- * @param day a EventRecurrence constant
- * @return day of week as a string
- */
- private static String dayToString(int day, int dayOfWeekLength) {
- return DateUtils.getDayOfWeekString(dayToUtilDay(day), dayOfWeekLength);
- }
-
- /**
- * Converts EventRecurrence's day of week to DateUtil's day of week.
- * @param day of week as an EventRecurrence value
- * @return day of week as a DateUtil value.
- */
- private static int dayToUtilDay(int day) {
- switch (day) {
- case EventRecurrence.SU: return Calendar.SUNDAY;
- case EventRecurrence.MO: return Calendar.MONDAY;
- case EventRecurrence.TU: return Calendar.TUESDAY;
- case EventRecurrence.WE: return Calendar.WEDNESDAY;
- case EventRecurrence.TH: return Calendar.THURSDAY;
- case EventRecurrence.FR: return Calendar.FRIDAY;
- case EventRecurrence.SA: return Calendar.SATURDAY;
- default: throw new IllegalArgumentException("bad day argument: " + day);
- }
- }
-}
diff --git a/src/com/android/calendar/ExpandableTextView.java b/src/com/android/calendar/ExpandableTextView.java
deleted file mode 100644
index 508528ec..00000000
--- a/src/com/android/calendar/ExpandableTextView.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2011 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.Context;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-public class ExpandableTextView extends LinearLayout implements OnClickListener {
-
- TextView mTv;
- ImageButton mButton; // Button to expand/collapse
-
- private boolean mRelayout = false;
- private boolean mCollapsed = true; // Show short version as default.
- private int mMaxCollapsedLines = 8; // The default number of lines;
- private Drawable mExpandDrawable;
- private Drawable mCollapseDrawable;
-
- public ExpandableTextView(Context context) {
- super(context);
- init();
- }
-
- public ExpandableTextView(Context context, AttributeSet attrs) {
- super(context, attrs, 0);
- init();
- }
-
- public ExpandableTextView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- init();
- }
-
- void init() {
- mMaxCollapsedLines = getResources().getInteger((R.integer.event_info_desc_line_num));
- mExpandDrawable = getResources().getDrawable(R.drawable.ic_expand_small_holo_light);
- mCollapseDrawable = getResources().getDrawable(R.drawable.ic_collapse_small_holo_light);
- }
-
- @Override
- public void onClick(View v) {
- if (mButton.getVisibility() != View.VISIBLE) {
- return;
- }
-
- mCollapsed = !mCollapsed;
- mButton.setImageDrawable(mCollapsed ? mExpandDrawable : mCollapseDrawable);
- mTv.setMaxLines(mCollapsed ? mMaxCollapsedLines : Integer.MAX_VALUE);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // If no change, measure and return
- if (!mRelayout || getVisibility() == View.GONE) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- return;
- }
- mRelayout = false;
-
- // Setup with optimistic case
- // i.e. Everything fits. No button needed
- mButton.setVisibility(View.GONE);
- mTv.setMaxLines(Integer.MAX_VALUE);
-
- // Measure
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- // If the text fits in collapsed mode, we are done.
- if (mTv.getLineCount() <= mMaxCollapsedLines) {
- return;
- }
-
- // Doesn't fit in collapsed mode. Collapse text view as needed. Show
- // button.
- if (mCollapsed) {
- mTv.setMaxLines(mMaxCollapsedLines);
- }
- mButton.setVisibility(View.VISIBLE);
-
- // Re-measure with new setup
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- private void findViews() {
- mTv = (TextView) findViewById(R.id.expandable_text);
- mTv.setOnClickListener(this);
- mButton = (ImageButton) findViewById(R.id.expand_collapse);
- mButton.setOnClickListener(this);
- }
-
- public void setText(String text) {
- mRelayout = true;
- if (mTv == null) {
- findViews();
- }
- String trimmedText = text.trim();
- mTv.setText(trimmedText);
- this.setVisibility(trimmedText.length() == 0 ? View.GONE : View.VISIBLE);
- }
-
- public CharSequence getText() {
- if (mTv == null) {
- return "";
- }
- return mTv.getText();
- }
-}
diff --git a/src/com/android/calendar/ExtensionsFactory.java b/src/com/android/calendar/ExtensionsFactory.java
deleted file mode 100644
index 697e2b4e..00000000
--- a/src/com/android/calendar/ExtensionsFactory.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2012 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.Context;
-import android.content.res.AssetManager;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-
-/*
- * Skeleton for additional options in the AllInOne menu.
- */
-public class ExtensionsFactory {
-
- private static String TAG = "ExtensionsFactory";
-
- // Config filename for mappings of various class names to their custom
- // implementations.
- private static String EXTENSIONS_PROPERTIES = "calendar_extensions.properties";
-
- private static String ALL_IN_ONE_MENU_KEY = "AllInOneMenuExtensions";
- private static String CLOUD_NOTIFICATION_KEY = "CloudNotificationChannel";
- private static String ANALYTICS_LOGGER_KEY = "AnalyticsLogger";
-
- private static Properties sProperties = new Properties();
- private static AllInOneMenuExtensionsInterface sAllInOneMenuExtensions = null;
- private static AnalyticsLogger sAnalyticsLogger = null;
-
- public static void init(AssetManager assetManager) {
- try {
- InputStream fileStream = assetManager.open(EXTENSIONS_PROPERTIES);
- sProperties.load(fileStream);
- fileStream.close();
- } catch (FileNotFoundException e) {
- // No custom extensions. Ignore.
- Log.d(TAG, "No custom extensions.");
- } catch (IOException e) {
- Log.d(TAG, e.toString());
- }
- }
-
- private static <T> T createInstance(String className) {
- try {
- Class<?> c = Class.forName(className);
- return (T) c.newInstance();
- } catch (ClassNotFoundException e) {
- Log.e(TAG, className + ": unable to create instance.", e);
- } catch (IllegalAccessException e) {
- Log.e(TAG, className + ": unable to create instance.", e);
- } catch (InstantiationException e) {
- Log.e(TAG, className + ": unable to create instance.", e);
- }
- return null;
- }
-
- public static AllInOneMenuExtensionsInterface getAllInOneMenuExtensions() {
- if ((sAllInOneMenuExtensions != null)) {
- return sAllInOneMenuExtensions;
- }
-
- String className = sProperties.getProperty(ALL_IN_ONE_MENU_KEY);
- if (className != null) {
- sAllInOneMenuExtensions = createInstance(className);
- } else {
- Log.d(TAG, ALL_IN_ONE_MENU_KEY + " not found in properties file.");
- }
-
- if (sAllInOneMenuExtensions == null) {
- sAllInOneMenuExtensions = new AllInOneMenuExtensionsInterface() {
- @Override
- public Integer getExtensionMenuResource(Menu menu) {
- return null;
- }
-
- @Override
- public boolean handleItemSelected(MenuItem item, Context context) {
- return false;
- }
- };
- }
- return sAllInOneMenuExtensions;
- }
-
- public static CloudNotificationBackplane getCloudNotificationBackplane() {
- CloudNotificationBackplane cnb = null;
-
- String className = sProperties.getProperty(CLOUD_NOTIFICATION_KEY);
- if (className != null) {
- cnb = createInstance(className);
- } else {
- Log.d(TAG, CLOUD_NOTIFICATION_KEY + " not found in properties file.");
- }
-
- if (cnb == null) {
- cnb = new CloudNotificationBackplane() {
- @Override
- public boolean open(Context context) {
- return true;
- }
-
- @Override
- public boolean subscribeToGroup(String senderId, String account, String groupId)
- throws IOException {
- return true;}
-
- @Override
- public void send(String to, String msgId, Bundle data) {
- }
-
- @Override
- public void close() {
- }
- };
- }
-
- return cnb;
- }
-
- public static AnalyticsLogger getAnalyticsLogger(Context context) {
- if (sAnalyticsLogger != null) {
- return sAnalyticsLogger;
- }
-
- String className = sProperties.getProperty(ANALYTICS_LOGGER_KEY);
- if (className != null) {
- sAnalyticsLogger = createInstance(className);
- } else {
- Log.d(TAG, ANALYTICS_LOGGER_KEY + " not found in properties file.");
- }
-
- if (sAnalyticsLogger == null) {
- sAnalyticsLogger = new AnalyticsLogger() {
- @Override
- public boolean initialize(Context context) {
- return true;
- }
-
- @Override
- public void trackView(String name) {
- }
- };
- }
-
- sAnalyticsLogger.initialize(context);
- return sAnalyticsLogger;
- }
-}
diff --git a/src/com/android/calendar/GeneralPreferences.java b/src/com/android/calendar/GeneralPreferences.java
index 54fc0e78..a42f07e3 100644
--- a/src/com/android/calendar/GeneralPreferences.java
+++ b/src/com/android/calendar/GeneralPreferences.java
@@ -118,7 +118,6 @@ public class GeneralPreferences extends PreferenceFragment implements
CheckBoxPreference mAlert;
CheckBoxPreference mVibrate;
- RingtonePreference mRingtone;
CheckBoxPreference mPopup;
CheckBoxPreference mUseHomeTZ;
CheckBoxPreference mHideDeclined;
@@ -165,17 +164,6 @@ public class GeneralPreferences extends PreferenceFragment implements
mAlertGroup.removePreference(mVibrate);
}
- mRingtone = (RingtonePreference) preferenceScreen.findPreference(KEY_ALERTS_RINGTONE);
- String ringToneUri = Utils.getRingTonePreference(activity);
-
- // Set the ringToneUri to the backup-able shared pref only so that
- // the Ringtone dialog will open up with the correct value.
- final Editor editor = preferenceScreen.getEditor();
- editor.putString(GeneralPreferences.KEY_ALERTS_RINGTONE, ringToneUri).apply();
-
- String ringtoneDisplayString = getRingtoneTitleFromUri(activity, ringToneUri);
- mRingtone.setSummary(ringtoneDisplayString == null ? "" : ringtoneDisplayString);
-
mPopup = (CheckBoxPreference) preferenceScreen.findPreference(KEY_ALERTS_POPUP);
mUseHomeTZ = (CheckBoxPreference) preferenceScreen.findPreference(KEY_HOME_TZ_ENABLED);
mHideDeclined = (CheckBoxPreference) preferenceScreen.findPreference(KEY_HIDE_DECLINED);
@@ -263,7 +251,6 @@ public class GeneralPreferences extends PreferenceFragment implements
mHomeTZ.setOnPreferenceChangeListener(listener);
mWeekStart.setOnPreferenceChangeListener(listener);
mDefaultReminder.setOnPreferenceChangeListener(listener);
- mRingtone.setOnPreferenceChangeListener(listener);
mHideDeclined.setOnPreferenceChangeListener(listener);
mVibrate.setOnPreferenceChangeListener(listener);
}
@@ -324,13 +311,6 @@ public class GeneralPreferences extends PreferenceFragment implements
} else if (preference == mDefaultReminder) {
mDefaultReminder.setValue((String) newValue);
mDefaultReminder.setSummary(mDefaultReminder.getEntry());
- } else if (preference == mRingtone) {
- if (newValue instanceof String) {
- Utils.setRingTonePreference(activity, (String) newValue);
- String ringtone = getRingtoneTitleFromUri(activity, (String) newValue);
- mRingtone.setSummary(ringtone == null ? "" : ringtone);
- }
- return true;
} else if (preference == mVibrate) {
mVibrate.setChecked((Boolean) newValue);
return true;
@@ -391,11 +371,9 @@ public class GeneralPreferences extends PreferenceFragment implements
private void updateChildPreferences() {
if (mAlert.isChecked()) {
mVibrate.setEnabled(true);
- mRingtone.setEnabled(true);
mPopup.setEnabled(true);
} else {
mVibrate.setEnabled(false);
- mRingtone.setEnabled(false);
mPopup.setEnabled(false);
}
}
@@ -405,17 +383,7 @@ public class GeneralPreferences extends PreferenceFragment implements
public boolean onPreferenceTreeClick(
PreferenceScreen preferenceScreen, Preference preference) {
final String key = preference.getKey();
- if (KEY_CLEAR_SEARCH_HISTORY.equals(key)) {
- SearchRecentSuggestions suggestions = new SearchRecentSuggestions(getActivity(),
- Utils.getSearchAuthority(getActivity()),
- CalendarRecentSuggestionsProvider.MODE);
- suggestions.clearHistory();
- Toast.makeText(getActivity(), R.string.search_history_cleared,
- Toast.LENGTH_SHORT).show();
- return true;
- } else {
- return super.onPreferenceTreeClick(preferenceScreen, preference);
- }
+ return super.onPreferenceTreeClick(preferenceScreen, preference);
}
@Override
diff --git a/src/com/android/calendar/GoogleCalendarUriIntentFilter.java b/src/com/android/calendar/GoogleCalendarUriIntentFilter.java
index fef89e8e..3970115b 100644
--- a/src/com/android/calendar/GoogleCalendarUriIntentFilter.java
+++ b/src/com/android/calendar/GoogleCalendarUriIntentFilter.java
@@ -19,227 +19,17 @@ package com.android.calendar;
import android.app.Activity;
import android.content.ActivityNotFoundException;
-import android.content.AsyncQueryHandler;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
import android.os.Bundle;
-import android.provider.CalendarContract;
-import android.provider.CalendarContract.Attendees;
-import android.provider.CalendarContract.Calendars;
-import android.provider.CalendarContract.Events;
-import android.text.TextUtils;
-import android.util.Base64;
-import android.util.Log;
-import android.widget.Toast;
-
-import com.android.calendarcommon2.DateException;
-import com.android.calendarcommon2.Duration;
public class GoogleCalendarUriIntentFilter extends Activity {
- private static final String TAG = "GoogleCalendarUriIntentFilter";
- static final boolean debug = false;
-
- 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 int EVENT_INDEX_DURATION = 3;
-
- private static final String[] EVENT_PROJECTION = new String[] {
- Events._ID, // 0
- Events.DTSTART, // 1
- Events.DTEND, // 2
- Events.DURATION, // 3
- };
-
- /**
- * Extracts the ID and calendar email from the eid parameter of a URI.
- *
- * The URI contains an "eid" parameter, which is comprised of an ID, followed
- * by a space, followed by the calendar email address. The domain is sometimes
- * shortened. See the switch statement. This is Base64-encoded before being
- * added to the URI.
- *
- * @param uri incoming request
- * @return the decoded event ID and calendar email
- */
- private String[] extractEidAndEmail(Uri uri) {
- try {
- String eidParam = uri.getQueryParameter("eid");
- if (debug) Log.d(TAG, "eid=" + eidParam );
- if (eidParam == null) {
- return null;
- }
-
- byte[] decodedBytes = Base64.decode(eidParam, Base64.DEFAULT);
- if (debug) Log.d(TAG, "decoded eid=" + new String(decodedBytes) );
-
- for (int spacePosn = 0; spacePosn < decodedBytes.length; spacePosn++) {
- if (decodedBytes[spacePosn] == ' ') {
- int emailLen = decodedBytes.length - spacePosn - 1;
- if (spacePosn == 0 || emailLen < 3) {
- break;
- }
-
- String domain = null;
- if (decodedBytes[decodedBytes.length - 2] == '@') {
- // Drop the special one character domain
- emailLen--;
-
- switch(decodedBytes[decodedBytes.length - 1]) {
- case 'm':
- domain = "gmail.com";
- break;
- case 'g':
- domain = "group.calendar.google.com";
- break;
- case 'h':
- domain = "holiday.calendar.google.com";
- break;
- case 'i':
- domain = "import.calendar.google.com";
- break;
- case 'v':
- domain = "group.v.calendar.google.com";
- break;
- default:
- Log.wtf(TAG, "Unexpected one letter domain: "
- + decodedBytes[decodedBytes.length - 1]);
- // Add sql wild card char to handle new cases
- // that we don't know about.
- domain = "%";
- break;
- }
- }
-
- String eid = new String(decodedBytes, 0, spacePosn);
- String email = new String(decodedBytes, spacePosn + 1, emailLen);
- if (debug) Log.d(TAG, "eid= " + eid );
- if (debug) Log.d(TAG, "email= " + email );
- if (debug) Log.d(TAG, "domain=" + domain );
- if (domain != null) {
- email += domain;
- }
-
- return new String[] { eid, email };
- }
- }
- } catch (RuntimeException e) {
- Log.w(TAG, "Punting malformed URI " + uri);
- }
- return null;
- }
-
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
Intent intent = getIntent();
if (intent != null) {
- Uri uri = intent.getData();
- if (uri != null) {
- String[] eidParts = extractEidAndEmail(uri);
- if (eidParts == null) {
- Log.i(TAG, "Could not find event for uri: " +uri);
- } else {
- final String syncId = eidParts[0];
- final String ownerAccount = eidParts[1];
- if (debug) Log.d(TAG, "eidParts=" + syncId + "/" + ownerAccount);
- final String selection = Events._SYNC_ID + " LIKE \"%" + syncId + "\" AND "
- + Calendars.OWNER_ACCOUNT + " LIKE \"" + ownerAccount + "\"";
-
- if (debug) Log.d(TAG, "selection: " + selection);
- Cursor eventCursor = getContentResolver().query(Events.CONTENT_URI,
- EVENT_PROJECTION, selection, null,
- Calendars.CALENDAR_ACCESS_LEVEL + " desc");
- if (debug) Log.d(TAG, "Found: " + eventCursor.getCount());
-
- if (eventCursor == null || eventCursor.getCount() == 0) {
- Log.i(TAG, "NOTE: found no matches on event with id='" + syncId + "'");
- return;
- }
- Log.i(TAG, "NOTE: found " + eventCursor.getCount()
- + " matches on event with id='" + syncId + "'");
- // Don't print eidPart[1] as it contains the user's PII
-
- try {
- // Get info from Cursor
- while (eventCursor.moveToNext()) {
- int eventId = eventCursor.getInt(EVENT_INDEX_ID);
- long startMillis = eventCursor.getLong(EVENT_INDEX_START);
- long endMillis = eventCursor.getLong(EVENT_INDEX_END);
- if (debug) Log.d(TAG, "_id: " + eventCursor.getLong(EVENT_INDEX_ID));
- if (debug) Log.d(TAG, "startMillis: " + startMillis);
- if (debug) Log.d(TAG, "endMillis: " + endMillis);
-
- if (endMillis == 0) {
- String duration = eventCursor.getString(EVENT_INDEX_DURATION);
- if (debug) Log.d(TAG, "duration: " + duration);
- if (TextUtils.isEmpty(duration)) {
- continue;
- }
-
- try {
- Duration d = new Duration();
- d.parse(duration);
- endMillis = startMillis + d.getMillis();
- if (debug) Log.d(TAG, "startMillis! " + startMillis);
- if (debug) Log.d(TAG, "endMillis! " + endMillis);
- if (endMillis < startMillis) {
- continue;
- }
- } catch (DateException e) {
- if (debug) Log.d(TAG, "duration:" + e.toString());
- continue;
- }
- }
-
- // Pick up attendee status action from uri clicked
- int attendeeStatus = Attendees.ATTENDEE_STATUS_NONE;
- if ("RESPOND".equals(uri.getQueryParameter("action"))) {
- try {
- switch (Integer.parseInt(uri.getQueryParameter("rst"))) {
- case 1: // Yes
- attendeeStatus = Attendees.ATTENDEE_STATUS_ACCEPTED;
- break;
- case 2: // No
- attendeeStatus = Attendees.ATTENDEE_STATUS_DECLINED;
- break;
- case 3: // Maybe
- attendeeStatus = Attendees.ATTENDEE_STATUS_TENTATIVE;
- break;
- }
- } catch (NumberFormatException e) {
- // ignore this error as if the response code
- // wasn't in the uri.
- }
- }
-
- final Uri calendarUri = ContentUris.withAppendedId(
- Events.CONTENT_URI, eventId);
- intent = new Intent(Intent.ACTION_VIEW, calendarUri);
- intent.setClass(this, EventInfoActivity.class);
- intent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, startMillis);
- intent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endMillis);
- if (attendeeStatus == Attendees.ATTENDEE_STATUS_NONE) {
- startActivity(intent);
- } else {
- updateSelfAttendeeStatus(
- eventId, ownerAccount, attendeeStatus, intent);
- }
- finish();
- return;
- }
- } finally {
- eventCursor.close();
- }
- }
- }
-
- // Can't handle the intent. Pass it on to the next Activity.
+ // Pass it on to the next Activity.
try {
startNextMatchingActivity(intent);
} catch (ActivityNotFoundException ex) {
@@ -248,44 +38,4 @@ public class GoogleCalendarUriIntentFilter extends Activity {
}
finish();
}
-
- private void updateSelfAttendeeStatus(
- int eventId, String ownerAccount, final int status, final Intent intent) {
- final ContentResolver cr = getContentResolver();
- final AsyncQueryHandler queryHandler =
- new AsyncQueryHandler(cr) {
- @Override
- protected void onUpdateComplete(int token, Object cookie, int result) {
- if (result == 0) {
- Log.w(TAG, "No rows updated - starting event viewer");
- intent.putExtra(Attendees.ATTENDEE_STATUS, status);
- startActivity(intent);
- return;
- }
- final int toastId;
- switch (status) {
- case Attendees.ATTENDEE_STATUS_ACCEPTED:
- toastId = R.string.rsvp_accepted;
- break;
- case Attendees.ATTENDEE_STATUS_DECLINED:
- toastId = R.string.rsvp_declined;
- break;
- case Attendees.ATTENDEE_STATUS_TENTATIVE:
- toastId = R.string.rsvp_tentative;
- break;
- default:
- return;
- }
- Toast.makeText(GoogleCalendarUriIntentFilter.this,
- toastId, Toast.LENGTH_LONG).show();
- }
- };
- final ContentValues values = new ContentValues();
- values.put(Attendees.ATTENDEE_STATUS, status);
- queryHandler.startUpdate(0, null,
- Attendees.CONTENT_URI,
- values,
- Attendees.ATTENDEE_EMAIL + "=? AND " + Attendees.EVENT_ID + "=?",
- new String[]{ ownerAccount, String.valueOf(eventId) });
- }
}
diff --git a/src/com/android/calendar/OtherPreferences.java b/src/com/android/calendar/OtherPreferences.java
index 2dd855d0..a59d3f46 100644
--- a/src/com/android/calendar/OtherPreferences.java
+++ b/src/com/android/calendar/OtherPreferences.java
@@ -72,7 +72,6 @@ public class OtherPreferences extends PreferenceFragment implements OnPreferenc
private static final String format12Hour = "%I:%M%P";
private Preference mCopyDb;
- private ListPreference mSkipReminders;
private CheckBoxPreference mQuietHours;
private Preference mQuietHoursStart;
private Preference mQuietHoursEnd;
@@ -96,13 +95,6 @@ public class OtherPreferences extends PreferenceFragment implements OnPreferenc
addPreferencesFromResource(R.xml.other_preferences);
mCopyDb = findPreference(KEY_OTHER_COPY_DB);
- mSkipReminders = (ListPreference) findPreference(KEY_OTHER_REMINDERS_RESPONDED);
- String skipPreferencesValue = null;
- if (mSkipReminders != null) {
- skipPreferencesValue = mSkipReminders.getValue();
- mSkipReminders.setOnPreferenceChangeListener(this);
- }
- updateSkipRemindersSummary(skipPreferencesValue);
Activity activity = getActivity();
if (activity == null) {
@@ -138,13 +130,6 @@ public class OtherPreferences extends PreferenceFragment implements OnPreferenc
@Override
public boolean onPreferenceChange(Preference preference, Object objValue) {
- final String key = preference.getKey();
-
- if (KEY_OTHER_REMINDERS_RESPONDED.equals(key)) {
- String value = String.valueOf(objValue);
- updateSkipRemindersSummary(value);
- }
-
return true;
}
@@ -222,30 +207,4 @@ public class OtherPreferences extends PreferenceFragment implements OnPreferenc
String format = mIs24HourMode? format24Hour : format12Hour;
return time.format(format);
}
-
- /**
- * Update the summary for the SkipReminders preference.
- * @param value The corresponding value of which summary to set. If null, the default summary
- * will be set, and the value will be set accordingly too.
- */
- private void updateSkipRemindersSummary(String value) {
- if (mSkipReminders != null) {
- // Default to "declined". Must match with R.array.preferences_skip_reminders_values.
- int index = 0;
-
- CharSequence[] values = mSkipReminders.getEntryValues();
- CharSequence[] entries = mSkipReminders.getEntries();
- for(int value_i = 0; value_i < values.length; value_i++) {
- if (values[value_i].equals(value)) {
- index = value_i;
- break;
- }
- }
- mSkipReminders.setSummary(entries[index].toString());
- if (value == null) {
- // Value was not known ahead of time, so the default value will be set.
- mSkipReminders.setValue(values[index].toString());
- }
- }
- }
}
diff --git a/src/com/android/calendar/QuickResponseSettings.java b/src/com/android/calendar/QuickResponseSettings.java
deleted file mode 100644
index 1e4e7547..00000000
--- a/src/com/android/calendar/QuickResponseSettings.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2012 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.app.Activity;
-import android.os.Bundle;
-import android.preference.EditTextPreference;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
-import android.preference.PreferenceFragment;
-import android.preference.PreferenceScreen;
-import android.util.Log;
-
-import java.util.Arrays;
-
-/**
- * Fragment to facilitate editing of quick responses when emailing guests
- *
- */
-public class QuickResponseSettings extends PreferenceFragment implements OnPreferenceChangeListener {
- private static final String TAG = "QuickResponseSettings";
-
- EditTextPreference[] mEditTextPrefs;
- String[] mResponses;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- PreferenceScreen ps = getPreferenceManager().createPreferenceScreen(getActivity());
- ps.setTitle(R.string.quick_response_settings_title);
-
- mResponses = Utils.getQuickResponses(getActivity());
-
- if (mResponses != null) {
- mEditTextPrefs = new EditTextPreference[mResponses.length];
-
- Arrays.sort(mResponses);
- int i = 0;
- for (String response : mResponses) {
- EditTextPreference et = new EditTextPreference(getActivity());
- et.setDialogTitle(R.string.quick_response_settings_edit_title);
- et.setTitle(response); // Display Text
- et.setText(response); // Value to edit
- et.setOnPreferenceChangeListener(this);
- mEditTextPrefs[i++] = et;
- ps.addPreference(et);
- }
- } else {
- Log.wtf(TAG, "No responses found");
- }
- setPreferenceScreen(ps);
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- ((CalendarSettingsActivity) activity).hideMenuButtons();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- CalendarSettingsActivity activity = (CalendarSettingsActivity) getActivity();
- if (!activity.isMultiPane()) {
- activity.setTitle(R.string.quick_response_settings_title);
- }
- }
-
- // Implements OnPreferenceChangeListener
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- for (int i = 0; i < mEditTextPrefs.length; i++) {
- if (mEditTextPrefs[i].compareTo(preference) == 0) {
- if (!mResponses[i].equals(newValue)) {
- mResponses[i] = (String) newValue;
- mEditTextPrefs[i].setTitle(mResponses[i]);
- mEditTextPrefs[i].setText(mResponses[i]);
- Utils.setSharedPreference(getActivity(), Utils.KEY_QUICK_RESPONSES, mResponses);
- }
- return true;
- }
- }
- return false;
- }
-}
diff --git a/src/com/android/calendar/RecipientAdapter.java b/src/com/android/calendar/RecipientAdapter.java
deleted file mode 100644
index bbff0486..00000000
--- a/src/com/android/calendar/RecipientAdapter.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.ex.chips.BaseRecipientAdapter;
-
-import android.accounts.Account;
-import android.content.Context;
-
-public class RecipientAdapter extends BaseRecipientAdapter {
- public RecipientAdapter(Context context) {
- super(context);
- }
-
- /**
- * Set the account when known. Causes the search to prioritize contacts from
- * that account.
- */
- public void setAccount(Account account) {
- if (account != null) {
- // TODO: figure out how to infer the contacts account
- // type from the email account
- super.setAccount(new android.accounts.Account(account.name, "unknown"));
- }
- }
-}
diff --git a/src/com/android/calendar/SearchActivity.java b/src/com/android/calendar/SearchActivity.java
deleted file mode 100644
index 929e4a61..00000000
--- a/src/com/android/calendar/SearchActivity.java
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.calendar;
-
-import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
-import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
-
-import android.app.ActionBar;
-import android.app.Activity;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
-import android.app.SearchManager;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.graphics.drawable.LayerDrawable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.provider.CalendarContract.Events;
-import android.provider.SearchRecentSuggestions;
-import android.text.format.Time;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MenuItem.OnActionExpandListener;
-import android.widget.SearchView;
-
-import com.android.calendar.CalendarController.EventInfo;
-import com.android.calendar.CalendarController.EventType;
-import com.android.calendar.CalendarController.ViewType;
-import com.android.calendar.agenda.AgendaFragment;
-
-public class SearchActivity extends Activity implements CalendarController.EventHandler,
- SearchView.OnQueryTextListener, OnActionExpandListener {
-
- private static final String TAG = SearchActivity.class.getSimpleName();
-
- private static final boolean DEBUG = false;
-
- private static final int HANDLER_KEY = 0;
-
- protected static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time";
-
- protected static final String BUNDLE_KEY_RESTORE_SEARCH_QUERY =
- "key_restore_search_query";
-
- // display event details to the side of the event list
- private boolean mShowEventDetailsWithAgenda;
- private static boolean mIsMultipane;
-
- private CalendarController mController;
-
- private EventInfoFragment mEventInfoFragment;
-
- private long mCurrentEventId = -1;
-
- private String mQuery;
-
- private SearchView mSearchView;
-
- private DeleteEventHelper mDeleteEventHelper;
-
- private Handler mHandler;
- private BroadcastReceiver mTimeChangesReceiver;
- private ContentResolver mContentResolver;
-
- private final ContentObserver mObserver = new ContentObserver(new Handler()) {
- @Override
- public boolean deliverSelfNotifications() {
- return true;
- }
-
- @Override
- public void onChange(boolean selfChange) {
- eventsChanged();
- }
- };
-
- // runs when a timezone was changed and updates the today icon
- private final Runnable mTimeChangesUpdater = new Runnable() {
- @Override
- public void run() {
- Utils.setMidnightUpdater(mHandler, mTimeChangesUpdater,
- Utils.getTimeZone(SearchActivity.this, mTimeChangesUpdater));
- SearchActivity.this.invalidateOptionsMenu();
- }
- };
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- // This needs to be created before setContentView
- mController = CalendarController.getInstance(this);
- mHandler = new Handler();
-
- mIsMultipane = Utils.getConfigBool(this, R.bool.multiple_pane_config);
- mShowEventDetailsWithAgenda =
- Utils.getConfigBool(this, R.bool.show_event_details_with_agenda);
-
- setContentView(R.layout.search);
-
- setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
-
- mContentResolver = getContentResolver();
-
- if (mIsMultipane) {
- getActionBar().setDisplayOptions(
- ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);
- } else {
- getActionBar().setDisplayOptions(0,
- ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
- }
-
- // Must be the first to register because this activity can modify the
- // list of event handlers in it's handle method. This affects who the
- // rest of the handlers the controller dispatches to are.
- mController.registerEventHandler(HANDLER_KEY, this);
-
- mDeleteEventHelper = new DeleteEventHelper(this, this,
- false /* don't exit when done */);
-
- long millis = 0;
- 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);
- }
- }
- if (millis == 0) {
- // Didn't find a time in the bundle, look in intent or current time
- millis = Utils.timeFromIntentInMillis(getIntent());
- }
-
- Intent intent = getIntent();
- if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
- String query;
- if (icicle != null && icicle.containsKey(BUNDLE_KEY_RESTORE_SEARCH_QUERY)) {
- query = icicle.getString(BUNDLE_KEY_RESTORE_SEARCH_QUERY);
- } else {
- query = intent.getStringExtra(SearchManager.QUERY);
- }
- if ("TARDIS".equalsIgnoreCase(query)) {
- Utils.tardis();
- }
- initFragments(millis, query);
- }
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- mController.deregisterAllEventHandlers();
- CalendarController.removeInstance(this);
- }
-
- private void initFragments(long timeMillis, String query) {
- FragmentManager fragmentManager = getFragmentManager();
- FragmentTransaction ft = fragmentManager.beginTransaction();
-
- AgendaFragment searchResultsFragment = new AgendaFragment(timeMillis, true);
- ft.replace(R.id.search_results, searchResultsFragment);
- mController.registerEventHandler(R.id.search_results, searchResultsFragment);
-
- ft.commit();
- Time t = new Time();
- t.set(timeMillis);
- search(query, t);
- }
-
- private void showEventInfo(EventInfo event) {
- if (mShowEventDetailsWithAgenda) {
- FragmentManager fragmentManager = getFragmentManager();
- FragmentTransaction ft = fragmentManager.beginTransaction();
-
- mEventInfoFragment = new EventInfoFragment(this, event.id,
- event.startTime.toMillis(false), event.endTime.toMillis(false),
- event.getResponse(), false, EventInfoFragment.DIALOG_WINDOW_STYLE,
- null /* No reminders to explicitly pass in. */);
- ft.replace(R.id.agenda_event_info, mEventInfoFragment);
- ft.commit();
- } else {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- Uri eventUri = ContentUris.withAppendedId(Events.CONTENT_URI, event.id);
- intent.setData(eventUri);
- intent.setClass(this, EventInfoActivity.class);
- intent.putExtra(EXTRA_EVENT_BEGIN_TIME,
- event.startTime != null ? event.startTime.toMillis(true) : -1);
- intent.putExtra(
- EXTRA_EVENT_END_TIME, event.endTime != null ? event.endTime.toMillis(true) : -1);
- startActivity(intent);
- }
- mCurrentEventId = event.id;
- }
-
- private void search(String searchQuery, Time goToTime) {
- // save query in recent queries
- SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
- Utils.getSearchAuthority(this),
- CalendarRecentSuggestionsProvider.MODE);
- suggestions.saveRecentQuery(searchQuery, null);
-
-
- EventInfo searchEventInfo = new EventInfo();
- searchEventInfo.eventType = EventType.SEARCH;
- searchEventInfo.query = searchQuery;
- searchEventInfo.viewType = ViewType.AGENDA;
- if (goToTime != null) {
- searchEventInfo.startTime = goToTime;
- }
- mController.sendEvent(this, searchEventInfo);
- mQuery = searchQuery;
- if (mSearchView != null) {
- mSearchView.setQuery(mQuery, false);
- mSearchView.clearFocus();
- }
- }
-
- private void deleteEvent(long eventId, long startMillis, long endMillis) {
- mDeleteEventHelper.delete(startMillis, endMillis, eventId, -1);
- if (mIsMultipane && mEventInfoFragment != null
- && eventId == mCurrentEventId) {
- FragmentManager fragmentManager = getFragmentManager();
- FragmentTransaction ft = fragmentManager.beginTransaction();
- ft.remove(mEventInfoFragment);
- ft.commit();
- mEventInfoFragment = null;
- mCurrentEventId = -1;
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- getMenuInflater().inflate(R.menu.search_title_bar, menu);
-
- // replace the default top layer drawable of the today icon with a custom drawable
- // that shows the day of the month of today
- MenuItem menuItem = menu.findItem(R.id.action_today);
- if (Utils.isJellybeanOrLater()) {
- LayerDrawable icon = (LayerDrawable) menuItem.getIcon();
- Utils.setTodayIcon(
- icon, this, Utils.getTimeZone(SearchActivity.this, mTimeChangesUpdater));
- } else {
- menuItem.setIcon(R.drawable.ic_menu_today_no_date_holo_light);
- }
-
- MenuItem item = menu.findItem(R.id.action_search);
- item.expandActionView();
- item.setOnActionExpandListener(this);
- mSearchView = (SearchView) item.getActionView();
- Utils.setUpSearchView(mSearchView, this);
- mSearchView.setQuery(mQuery, false);
- mSearchView.clearFocus();
-
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- Time t = null;
- final int itemId = item.getItemId();
- if (itemId == R.id.action_today) {
- t = new Time();
- t.setToNow();
- mController.sendEvent(this, EventType.GO_TO, t, null, -1, ViewType.CURRENT);
- return true;
- } else if (itemId == R.id.action_search) {
- return false;
- } else if (itemId == R.id.action_settings) {
- mController.sendEvent(this, EventType.LAUNCH_SETTINGS, null, null, 0, 0);
- return true;
- } else if (itemId == android.R.id.home) {
- Utils.returnToCalendarHome(this);
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- // From the Android Dev Guide: "It's important to note that when
- // onNewIntent(Intent) is called, the Activity has not been restarted,
- // so the getIntent() method will still return the Intent that was first
- // received with onCreate(). This is why setIntent(Intent) is called
- // inside onNewIntent(Intent) (just in case you call getIntent() at a
- // later time)."
- setIntent(intent);
- handleIntent(intent);
- }
-
- private void handleIntent(Intent intent) {
- if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
- String query = intent.getStringExtra(SearchManager.QUERY);
- search(query, null);
- }
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putLong(BUNDLE_KEY_RESTORE_TIME, mController.getTime());
- outState.putString(BUNDLE_KEY_RESTORE_SEARCH_QUERY, mQuery);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- Utils.setMidnightUpdater(
- mHandler, mTimeChangesUpdater, Utils.getTimeZone(this, mTimeChangesUpdater));
- // Make sure the today icon is up to date
- invalidateOptionsMenu();
- mTimeChangesReceiver = Utils.setTimeChangesReceiver(this, mTimeChangesUpdater);
- mContentResolver.registerContentObserver(Events.CONTENT_URI, true, mObserver);
- // We call this in case the user changed the time zone
- eventsChanged();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- Utils.resetMidnightUpdater(mHandler, mTimeChangesUpdater);
- Utils.clearTimeChangesReceiver(this, mTimeChangesReceiver);
- mContentResolver.unregisterContentObserver(mObserver);
- }
-
- @Override
- public void eventsChanged() {
- mController.sendEvent(this, EventType.EVENTS_CHANGED, null, null, -1, ViewType.CURRENT);
- }
-
- @Override
- public long getSupportedEventTypes() {
- return EventType.VIEW_EVENT | EventType.DELETE_EVENT;
- }
-
- @Override
- public void handleEvent(EventInfo event) {
- long endTime = (event.endTime == null) ? -1 : event.endTime.toMillis(false);
- if (event.eventType == EventType.VIEW_EVENT) {
- showEventInfo(event);
- } else if (event.eventType == EventType.DELETE_EVENT) {
- deleteEvent(event.id, event.startTime.toMillis(false), endTime);
- }
- }
-
- @Override
- public boolean onQueryTextChange(String newText) {
- return false;
- }
-
- @Override
- public boolean onQueryTextSubmit(String query) {
- mQuery = query;
- mController.sendEvent(this, EventType.SEARCH, null, null, -1, ViewType.CURRENT, 0, query,
- getComponentName());
- return false;
- }
-
- @Override
- public boolean onMenuItemActionExpand(MenuItem item) {
- return true;
- }
-
- @Override
- public boolean onMenuItemActionCollapse(MenuItem item) {
- Utils.returnToCalendarHome(this);
- return false;
- }
-}
diff --git a/src/com/android/calendar/Utils.java b/src/com/android/calendar/Utils.java
index 41961852..cc55c999 100644
--- a/src/com/android/calendar/Utils.java
+++ b/src/com/android/calendar/Utils.java
@@ -50,10 +50,8 @@ import android.text.format.Time;
import android.text.style.URLSpan;
import android.text.util.Linkify;
import android.util.Log;
-import android.widget.SearchView;
import com.android.calendar.CalendarController.ViewType;
-import com.android.calendar.CalendarEventModel.ReminderEntry;
import com.android.calendar.CalendarUtils.TimeZoneUtils;
import java.util.ArrayList;
@@ -254,13 +252,6 @@ public class Utils {
}
/**
- * Gets the intent action for telling the widget to update.
- */
- public static String getSearchAuthority(Context context) {
- return context.getPackageName() + ".CalendarRecentSuggestionsProvider";
- }
-
- /**
* Writes a new home time zone to the db. Updates the home time zone in the
* db asynchronously and updates the local cache. Sending a time zone of
* **tbd** will cause it to be set to the device's time zone. null or empty
@@ -401,41 +392,6 @@ public class Utils {
prefs.edit().remove(key).apply();
}
- // The backed up ring tone preference should not used because it is a device
- // specific Uri. The preference now lives in a separate non-backed-up
- // shared_pref file (SHARED_PREFS_NAME_NO_BACKUP). The preference in the old
- // backed-up shared_pref file (SHARED_PREFS_NAME) is used only to control the
- // default value when the ringtone dialog opens up.
- //
- // At backup manager "restore" time (which should happen before launcher
- // comes up for the first time), the value will be set/reset to default
- // ringtone.
- public static String getRingTonePreference(Context context) {
- SharedPreferences prefs = context.getSharedPreferences(
- GeneralPreferences.SHARED_PREFS_NAME_NO_BACKUP, Context.MODE_PRIVATE);
- String ringtone = prefs.getString(GeneralPreferences.KEY_ALERTS_RINGTONE, null);
-
- // If it hasn't been populated yet, that means new code is running for
- // the first time and restore hasn't happened. Migrate value from
- // backed-up shared_pref to non-shared_pref.
- if (ringtone == null) {
- // Read from the old place with a default of DEFAULT_RINGTONE
- ringtone = getSharedPreference(context, GeneralPreferences.KEY_ALERTS_RINGTONE,
- GeneralPreferences.DEFAULT_RINGTONE);
-
- // Write it to the new place
- setRingTonePreference(context, ringtone);
- }
-
- return ringtone;
- }
-
- public static void setRingTonePreference(Context context, String value) {
- SharedPreferences prefs = context.getSharedPreferences(
- GeneralPreferences.SHARED_PREFS_NAME_NO_BACKUP, Context.MODE_PRIVATE);
- prefs.edit().putString(GeneralPreferences.KEY_ALERTS_RINGTONE, value).apply();
- }
-
/**
* Save default agenda/day/week/month view for next time
*
@@ -774,39 +730,6 @@ public class Utils {
return recycle.normalize(true);
}
- /**
- * Scan through a cursor of calendars and check if names are duplicated.
- * This travels a cursor containing calendar display names and fills in the
- * provided map with whether or not each name is repeated.
- *
- * @param isDuplicateName The map to put the duplicate check results in.
- * @param cursor The query of calendars to check
- * @param nameIndex The column of the query that contains the display name
- */
- public static void checkForDuplicateNames(
- Map<String, Boolean> isDuplicateName, Cursor cursor, int nameIndex) {
- isDuplicateName.clear();
- cursor.moveToPosition(-1);
- while (cursor.moveToNext()) {
- String displayName = cursor.getString(nameIndex);
- // Set it to true if we've seen this name before, false otherwise
- if (displayName != null) {
- isDuplicateName.put(displayName, isDuplicateName.containsKey(displayName));
- }
- }
- }
-
- /**
- * Null-safe object comparison
- *
- * @param s1
- * @param s2
- * @return
- */
- public static boolean equals(Object o1, Object o2) {
- return o1 == null ? o2 == null : o1.equals(o2);
- }
-
public static void setAllowWeekForDetailView(boolean allowWeekView) {
mAllowWeekForDetailView = allowWeekView;
}
@@ -1305,19 +1228,6 @@ public class Utils {
}
/**
- * This sets up a search view to use Calendar's search suggestions provider
- * and to allow refining the search.
- *
- * @param view The {@link SearchView} to set up
- * @param act The activity using the view
- */
- public static void setUpSearchView(SearchView view, Activity act) {
- SearchManager searchManager = (SearchManager) act.getSystemService(Context.SEARCH_SERVICE);
- view.setSearchableInfo(searchManager.getSearchableInfo(act.getComponentName()));
- view.setQueryRefinementEnabled(true);
- }
-
- /**
* Given a context and a time in millis since unix epoch figures out the
* correct week of the year for that time.
*
@@ -1531,116 +1441,6 @@ public class Utils {
}
/**
- * Create an intent for emailing attendees of an event.
- *
- * @param resources The resources for translating strings.
- * @param eventTitle The title of the event to use as the email subject.
- * @param body The default text for the email body.
- * @param toEmails The list of emails for the 'to' line.
- * @param ccEmails The list of emails for the 'cc' line.
- * @param ownerAccount The owner account to use as the email sender.
- */
- public static Intent createEmailAttendeesIntent(Resources resources, String eventTitle,
- String body, List<String> toEmails, List<String> ccEmails, String ownerAccount) {
- List<String> toList = toEmails;
- List<String> ccList = ccEmails;
- if (toEmails.size() <= 0) {
- if (ccEmails.size() <= 0) {
- // TODO: Return a SEND intent if no one to email to, to at least populate
- // a draft email with the subject (and no recipients).
- throw new IllegalArgumentException("Both toEmails and ccEmails are empty.");
- }
-
- // Email app does not work with no "to" recipient. Move all 'cc' to 'to'
- // in this case.
- toList = ccEmails;
- ccList = null;
- }
-
- // Use the event title as the email subject (prepended with 'Re: ').
- String subject = null;
- if (eventTitle != null) {
- subject = resources.getString(R.string.email_subject_prefix) + eventTitle;
- }
-
- // Use the SENDTO intent with a 'mailto' URI, because using SEND will cause
- // the picker to show apps like text messaging, which does not make sense
- // for email addresses. We put all data in the URI instead of using the extra
- // Intent fields (ie. EXTRA_CC, etc) because some email apps might not handle
- // those (though gmail does).
- Uri.Builder uriBuilder = new Uri.Builder();
- uriBuilder.scheme("mailto");
-
- // We will append the first email to the 'mailto' field later (because the
- // current state of the Email app requires it). Add the remaining 'to' values
- // here. When the email codebase is updated, we can simplify this.
- if (toList.size() > 1) {
- for (int i = 1; i < toList.size(); i++) {
- // The Email app requires repeated parameter settings instead of
- // a single comma-separated list.
- uriBuilder.appendQueryParameter("to", toList.get(i));
- }
- }
-
- // Add the subject parameter.
- if (subject != null) {
- uriBuilder.appendQueryParameter("subject", subject);
- }
-
- // Add the subject parameter.
- if (body != null) {
- uriBuilder.appendQueryParameter("body", body);
- }
-
- // Add the cc parameters.
- if (ccList != null && ccList.size() > 0) {
- for (String email : ccList) {
- uriBuilder.appendQueryParameter("cc", email);
- }
- }
-
- // Insert the first email after 'mailto:' in the URI manually since Uri.Builder
- // doesn't seem to have a way to do this.
- String uri = uriBuilder.toString();
- if (uri.startsWith("mailto:")) {
- StringBuilder builder = new StringBuilder(uri);
- builder.insert(7, Uri.encode(toList.get(0)));
- uri = builder.toString();
- }
-
- // Start the email intent. Email from the account of the calendar owner in case there
- // are multiple email accounts.
- Intent emailIntent = new Intent(android.content.Intent.ACTION_SENDTO, Uri.parse(uri));
- emailIntent.putExtra("fromAccountString", ownerAccount);
-
- // Workaround a Email bug that overwrites the body with this intent extra. If not
- // set, it clears the body.
- if (body != null) {
- emailIntent.putExtra(Intent.EXTRA_TEXT, body);
- }
-
- return Intent.createChooser(emailIntent, resources.getString(R.string.email_picker_label));
- }
-
- /**
- * Example fake email addresses used as attendee emails are resources like conference rooms,
- * or another calendar, etc. These all end in "calendar.google.com".
- */
- public static boolean isValidEmail(String email) {
- return email != null && !email.endsWith(MACHINE_GENERATED_ADDRESS);
- }
-
- /**
- * Returns true if:
- * (1) the email is not a resource like a conference room or another calendar.
- * Catch most of these by filtering out suffix calendar.google.com.
- * (2) the email is not equal to the sync account to prevent mailing himself.
- */
- public static boolean isEmailableFrom(String email, String syncAccountName) {
- return Utils.isValidEmail(email) && !email.equals(syncAccountName);
- }
-
- /**
* Inserts a drawable with today's day into the today's icon in the option menu
* @param icon - today's icon from the options menu
*/
@@ -1663,43 +1463,6 @@ public class Utils {
icon.setDrawableByLayerId(R.id.today_icon_day, today);
}
- private static class CalendarBroadcastReceiver extends BroadcastReceiver {
-
- Runnable mCallBack;
-
- public CalendarBroadcastReceiver(Runnable callback) {
- super();
- mCallBack = callback;
- }
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED) ||
- intent.getAction().equals(Intent.ACTION_TIME_CHANGED) ||
- intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED) ||
- intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
- if (mCallBack != null) {
- mCallBack.run();
- }
- }
- }
- }
-
- public static BroadcastReceiver setTimeChangesReceiver(Context c, Runnable callback) {
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_TIME_CHANGED);
- filter.addAction(Intent.ACTION_DATE_CHANGED);
- filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
- filter.addAction(Intent.ACTION_LOCALE_CHANGED);
-
- CalendarBroadcastReceiver r = new CalendarBroadcastReceiver(callback);
- c.registerReceiver(r, filter);
- return r;
- }
-
- public static void clearTimeChangesReceiver(Context c, BroadcastReceiver r) {
- c.unregisterReceiver(r);
- }
-
/**
* Get a list of quick responses used for emailing guests from the
* SharedPreferences. If not are found, get the hard coded ones that shipped
@@ -1733,394 +1496,4 @@ public class Utils {
}
return sVersion;
}
-
- /**
- * Checks the server for an updated list of Calendars (in the background).
- *
- * 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 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 and fragment are started.
- *
- * @param account - The account to sync. May be null to sync all accounts.
- */
- public static void startCalendarMetafeedSync(Account account) {
- Bundle extras = new Bundle();
- extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
- extras.putBoolean("metafeedonly", true);
- ContentResolver.requestSync(account, Calendars.CONTENT_URI.getAuthority(), extras);
- }
-
- /**
- * Replaces stretches of text that look like addresses and phone numbers with clickable
- * links. If lastDitchGeo is true, then if no links are found in the textview, the entire
- * string will be converted to a single geo link. Any spans that may have previously been
- * in the text will be cleared out.
- * <p>
- * This is really just an enhanced version of Linkify.addLinks().
- *
- * @param text - The string to search for links.
- * @param lastDitchGeo - If no links are found, turn the entire string into one geo link.
- * @return Spannable object containing the list of URL spans found.
- */
- public static Spannable extendedLinkify(String text, boolean lastDitchGeo) {
- // We use a copy of the string argument so it's available for later if necessary.
- Spannable spanText = SpannableString.valueOf(text);
-
- /*
- * If the text includes a street address like "1600 Amphitheater Parkway, 94043",
- * the current Linkify code will identify "94043" as a phone number and invite
- * you to dial it (and not provide a map link for the address). For outside US,
- * use Linkify result iff it spans the entire text. Otherwise send the user to maps.
- */
- String defaultPhoneRegion = System.getProperty("user.region", "US");
- if (!defaultPhoneRegion.equals("US")) {
- Linkify.addLinks(spanText, Linkify.ALL);
-
- // If Linkify links the entire text, use that result.
- URLSpan[] spans = spanText.getSpans(0, spanText.length(), URLSpan.class);
- if (spans.length == 1) {
- int linkStart = spanText.getSpanStart(spans[0]);
- int linkEnd = spanText.getSpanEnd(spans[0]);
- if (linkStart <= indexFirstNonWhitespaceChar(spanText) &&
- linkEnd >= indexLastNonWhitespaceChar(spanText) + 1) {
- return spanText;
- }
- }
-
- // Otherwise, to be cautious and to try to prevent false positives, reset the spannable.
- spanText = SpannableString.valueOf(text);
- // If lastDitchGeo is true, default the entire string to geo.
- if (lastDitchGeo && !text.isEmpty()) {
- Linkify.addLinks(spanText, mWildcardPattern, "geo:0,0?q=");
- }
- return spanText;
- }
-
- /*
- * For within US, we want to have better recognition of phone numbers without losing
- * any of the existing annotations. Ideally this would be addressed by improving Linkify.
- * For now we manage it as a second pass over the text.
- *
- * URIs and e-mail addresses are pretty easy to pick out of text. Phone numbers
- * are a bit tricky because they have radically different formats in different
- * countries, in terms of both the digits and the way in which they are commonly
- * written or presented (e.g. the punctuation and spaces in "(650) 555-1212").
- * The expected format of a street address is defined in WebView.findAddress(). It's
- * pretty narrowly defined, so it won't often match.
- *
- * The RFC 3966 specification defines the format of a "tel:" URI.
- *
- * Start by letting Linkify find anything that isn't a phone number. We have to let it
- * run first because every invocation removes all previous URLSpan annotations.
- *
- * Ideally we'd use the external/libphonenumber routines, but those aren't available
- * to unbundled applications.
- */
- boolean linkifyFoundLinks = Linkify.addLinks(spanText,
- Linkify.ALL & ~(Linkify.PHONE_NUMBERS));
-
- /*
- * Get a list of any spans created by Linkify, for the coordinate overlapping span check.
- */
- URLSpan[] existingSpans = spanText.getSpans(0, spanText.length(), URLSpan.class);
-
- /*
- * Check for coordinates.
- * This must be done before phone numbers because longitude may look like a phone number.
- */
- Matcher coordMatcher = COORD_PATTERN.matcher(spanText);
- int coordCount = 0;
- while (coordMatcher.find()) {
- int start = coordMatcher.start();
- int end = coordMatcher.end();
- if (spanWillOverlap(spanText, existingSpans, start, end)) {
- continue;
- }
-
- URLSpan span = new URLSpan("geo:0,0?q=" + coordMatcher.group());
- spanText.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- coordCount++;
- }
-
- /*
- * Update the list of existing spans, for the phone number overlapping span check.
- */
- existingSpans = spanText.getSpans(0, spanText.length(), URLSpan.class);
-
- /*
- * Search for phone numbers.
- *
- * Some URIs contain strings of digits that look like phone numbers. If both the URI
- * scanner and the phone number scanner find them, we want the URI link to win. Since
- * the URI scanner runs first, we just need to avoid creating overlapping spans.
- */
- int[] phoneSequences = findNanpPhoneNumbers(text);
-
- /*
- * Insert spans for the numbers we found. We generate "tel:" URIs.
- */
- int phoneCount = 0;
- for (int match = 0; match < phoneSequences.length / 2; match++) {
- int start = phoneSequences[match*2];
- int end = phoneSequences[match*2 + 1];
-
- if (spanWillOverlap(spanText, existingSpans, start, end)) {
- continue;
- }
-
- /*
- * The Linkify code takes the matching span and strips out everything that isn't a
- * digit or '+' sign. We do the same here. Extension numbers will get appended
- * without a separator, but the dialer wasn't doing anything useful with ";ext="
- * anyway.
- */
-
- //String dialStr = phoneUtil.format(match.number(),
- // PhoneNumberUtil.PhoneNumberFormat.RFC3966);
- StringBuilder dialBuilder = new StringBuilder();
- for (int i = start; i < end; i++) {
- char ch = spanText.charAt(i);
- if (ch == '+' || Character.isDigit(ch)) {
- dialBuilder.append(ch);
- }
- }
- URLSpan span = new URLSpan("tel:" + dialBuilder.toString());
-
- spanText.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- phoneCount++;
- }
-
- /*
- * If lastDitchGeo, and no other links have been found, set the entire string as a geo link.
- */
- if (lastDitchGeo && !text.isEmpty() &&
- !linkifyFoundLinks && phoneCount == 0 && coordCount == 0) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "No linkification matches, using geo default");
- }
- Linkify.addLinks(spanText, mWildcardPattern, "geo:0,0?q=");
- }
-
- return spanText;
- }
-
- private static int indexFirstNonWhitespaceChar(CharSequence str) {
- for (int i = 0; i < str.length(); i++) {
- if (!Character.isWhitespace(str.charAt(i))) {
- return i;
- }
- }
- return -1;
- }
-
- private static int indexLastNonWhitespaceChar(CharSequence str) {
- for (int i = str.length() - 1; i >= 0; i--) {
- if (!Character.isWhitespace(str.charAt(i))) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Finds North American Numbering Plan (NANP) phone numbers in the input text.
- *
- * @param text The text to scan.
- * @return A list of [start, end) pairs indicating the positions of phone numbers in the input.
- */
- // @VisibleForTesting
- static int[] findNanpPhoneNumbers(CharSequence text) {
- ArrayList<Integer> list = new ArrayList<Integer>();
-
- int startPos = 0;
- int endPos = text.length() - NANP_MIN_DIGITS + 1;
- if (endPos < 0) {
- return new int[] {};
- }
-
- /*
- * We can't just strip the whitespace out and crunch it down, because the whitespace
- * is significant. March through, trying to figure out where numbers start and end.
- */
- while (startPos < endPos) {
- // skip whitespace
- while (Character.isWhitespace(text.charAt(startPos)) && startPos < endPos) {
- startPos++;
- }
- if (startPos == endPos) {
- break;
- }
-
- // check for a match at this position
- int matchEnd = findNanpMatchEnd(text, startPos);
- if (matchEnd > startPos) {
- list.add(startPos);
- list.add(matchEnd);
- startPos = matchEnd; // skip past match
- } else {
- // skip to next whitespace char
- while (!Character.isWhitespace(text.charAt(startPos)) && startPos < endPos) {
- startPos++;
- }
- }
- }
-
- int[] result = new int[list.size()];
- for (int i = list.size() - 1; i >= 0; i--) {
- result[i] = list.get(i);
- }
- return result;
- }
-
- /**
- * Checks to see if there is a valid phone number in the input, starting at the specified
- * offset. If so, the index of the last character + 1 is returned. The input is assumed
- * to begin with a non-whitespace character.
- *
- * @return Exclusive end position, or -1 if not a match.
- */
- private static int findNanpMatchEnd(CharSequence text, int startPos) {
- /*
- * A few interesting cases:
- * 94043 # too short, ignore
- * 123456789012 # too long, ignore
- * +1 (650) 555-1212 # 11 digits, spaces
- * (650) 555 5555 # Second space, only when first is present.
- * (650) 555-1212, (650) 555-1213 # two numbers, return first
- * 1-650-555-1212 # 11 digits with leading '1'
- * *#650.555.1212#*! # 10 digits, include #*, ignore trailing '!'
- * 555.1212 # 7 digits
- *
- * For the most part we want to break on whitespace, but it's common to leave a space
- * between the initial '1' and/or after the area code.
- */
-
- // Check for "tel:" URI prefix.
- if (text.length() > startPos+4
- && text.subSequence(startPos, startPos+4).toString().equalsIgnoreCase("tel:")) {
- startPos += 4;
- }
-
- int endPos = text.length();
- int curPos = startPos;
- int foundDigits = 0;
- char firstDigit = 'x';
- boolean foundWhiteSpaceAfterAreaCode = false;
-
- while (curPos <= endPos) {
- char ch;
- if (curPos < endPos) {
- ch = text.charAt(curPos);
- } else {
- ch = 27; // fake invalid symbol at end to trigger loop break
- }
-
- if (Character.isDigit(ch)) {
- if (foundDigits == 0) {
- firstDigit = ch;
- }
- foundDigits++;
- if (foundDigits > NANP_MAX_DIGITS) {
- // too many digits, stop early
- return -1;
- }
- } else if (Character.isWhitespace(ch)) {
- if ( (firstDigit == '1' && foundDigits == 4) ||
- (foundDigits == 3)) {
- foundWhiteSpaceAfterAreaCode = true;
- } else if (firstDigit == '1' && foundDigits == 1) {
- } else if (foundWhiteSpaceAfterAreaCode
- && ( (firstDigit == '1' && (foundDigits == 7)) || (foundDigits == 6))) {
- } else {
- break;
- }
- } else if (NANP_ALLOWED_SYMBOLS.indexOf(ch) == -1) {
- break;
- }
- // else it's an allowed symbol
-
- curPos++;
- }
-
- if ((firstDigit != '1' && (foundDigits == 7 || foundDigits == 10)) ||
- (firstDigit == '1' && foundDigits == 11)) {
- // match
- return curPos;
- }
-
- return -1;
- }
-
- /**
- * Determines whether a new span at [start,end) will overlap with any existing span.
- */
- private static boolean spanWillOverlap(Spannable spanText, URLSpan[] spanList, int start,
- int end) {
- if (start == end) {
- // empty span, ignore
- return false;
- }
- for (URLSpan span : spanList) {
- int existingStart = spanText.getSpanStart(span);
- int existingEnd = spanText.getSpanEnd(span);
- if ((start >= existingStart && start < existingEnd) ||
- end > existingStart && end <= existingEnd) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- CharSequence seq = spanText.subSequence(start, end);
- Log.v(TAG, "Not linkifying " + seq + " as phone number due to overlap");
- }
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * @param bundle The incoming bundle that contains the reminder info.
- * @return ArrayList<ReminderEntry> of the reminder minutes and methods.
- */
- public static ArrayList<ReminderEntry> readRemindersFromBundle(Bundle bundle) {
- ArrayList<ReminderEntry> reminders = null;
-
- ArrayList<Integer> reminderMinutes = bundle.getIntegerArrayList(
- EventInfoFragment.BUNDLE_KEY_REMINDER_MINUTES);
- ArrayList<Integer> reminderMethods = bundle.getIntegerArrayList(
- EventInfoFragment.BUNDLE_KEY_REMINDER_METHODS);
- if (reminderMinutes == null || reminderMethods == null) {
- if (reminderMinutes != null || reminderMethods != null) {
- String nullList = (reminderMinutes == null?
- "reminderMinutes" : "reminderMethods");
- Log.d(TAG, String.format("Error resolving reminders: %s was null",
- nullList));
- }
- return null;
- }
-
- int numReminders = reminderMinutes.size();
- if (numReminders == reminderMethods.size()) {
- // Only if the size of the reminder minutes we've read in is
- // the same as the size of the reminder methods. Otherwise,
- // something went wrong with bundling them.
- reminders = new ArrayList<ReminderEntry>(numReminders);
- for (int reminder_i = 0; reminder_i < numReminders;
- reminder_i++) {
- int minutes = reminderMinutes.get(reminder_i);
- int method = reminderMethods.get(reminder_i);
- reminders.add(ReminderEntry.valueOf(minutes, method));
- }
- } else {
- Log.d(TAG, String.format("Error resolving reminders." +
- " Found %d reminderMinutes, but %d reminderMethods.",
- numReminders, reminderMethods.size()));
- }
-
- return reminders;
- }
-
}
diff --git a/src/com/android/calendar/agenda/AgendaAdapter.java b/src/com/android/calendar/agenda/AgendaAdapter.java
deleted file mode 100644
index 9e492832..00000000
--- a/src/com/android/calendar/agenda/AgendaAdapter.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * 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.agenda;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.provider.CalendarContract.Attendees;
-import android.text.TextUtils;
-import android.text.format.DateFormat;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.ResourceCursorAdapter;
-import android.widget.TextView;
-
-import com.android.calendar.ColorChipView;
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-
-import java.util.Formatter;
-import java.util.Locale;
-import java.util.TimeZone;
-
-public class AgendaAdapter extends ResourceCursorAdapter {
- private final String mNoTitleLabel;
- private final Resources mResources;
- private final int mDeclinedColor;
- private final int mStandardColor;
- private final int mWhereColor;
- private final int mWhereDeclinedColor;
- // Note: Formatter is not thread safe. Fine for now as it is only used by the main thread.
- private final Formatter mFormatter;
- private final StringBuilder mStringBuilder;
- private float mScale;
-
- private int COLOR_CHIP_ALL_DAY_HEIGHT;
- private int COLOR_CHIP_HEIGHT;
-
- private final Runnable mTZUpdater = new Runnable() {
- @Override
- public void run() {
- notifyDataSetChanged();
- }
- };
-
- static class ViewHolder {
-
- public static final int DECLINED_RESPONSE = 0;
- public static final int TENTATIVE_RESPONSE = 1;
- public static final int ACCEPTED_RESPONSE = 2;
-
- /* Event */
- TextView title;
- TextView when;
- TextView where;
- View selectedMarker;
- LinearLayout textContainer;
- long instanceId;
- ColorChipView colorChip;
- long startTimeMilli;
- boolean allDay;
- boolean grayed;
- int julianDay;
- }
-
- public AgendaAdapter(Context context, int resource) {
- super(context, resource, null);
-
- mResources = context.getResources();
- mNoTitleLabel = mResources.getString(R.string.no_title_label);
- mDeclinedColor = mResources.getColor(R.color.agenda_item_declined_color);
- mStandardColor = mResources.getColor(R.color.agenda_item_standard_color);
- mWhereDeclinedColor = mResources.getColor(R.color.agenda_item_where_declined_text_color);
- mWhereColor = mResources.getColor(R.color.agenda_item_where_text_color);
- mStringBuilder = new StringBuilder(50);
- mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
-
- COLOR_CHIP_ALL_DAY_HEIGHT = mResources.getInteger(R.integer.color_chip_all_day_height);
- COLOR_CHIP_HEIGHT = mResources.getInteger(R.integer.color_chip_height);
- if (mScale == 0) {
- mScale = mResources.getDisplayMetrics().density;
- if (mScale != 1) {
- COLOR_CHIP_ALL_DAY_HEIGHT *= mScale;
- COLOR_CHIP_HEIGHT *= mScale;
- }
- }
-
- }
-
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- 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();
- view.setTag(holder);
- holder.title = (TextView) view.findViewById(R.id.title);
- holder.when = (TextView) view.findViewById(R.id.when);
- holder.where = (TextView) view.findViewById(R.id.where);
- holder.textContainer = (LinearLayout)
- view.findViewById(R.id.agenda_item_text_container);
- holder.selectedMarker = view.findViewById(R.id.selected_marker);
- holder.colorChip = (ColorChipView)view.findViewById(R.id.agenda_item_color);
- }
-
- holder.startTimeMilli = cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
- // Fade text if event was declined and set the color chip mode (response
- boolean allDay = cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
- holder.allDay = allDay;
- int selfAttendeeStatus = cursor.getInt(AgendaWindowAdapter.INDEX_SELF_ATTENDEE_STATUS);
- if (selfAttendeeStatus == Attendees.ATTENDEE_STATUS_DECLINED) {
- holder.title.setTextColor(mDeclinedColor);
- holder.when.setTextColor(mWhereDeclinedColor);
- holder.where.setTextColor(mWhereDeclinedColor);
- holder.colorChip.setDrawStyle(ColorChipView.DRAW_FADED);
- } else {
- holder.title.setTextColor(mStandardColor);
- holder.when.setTextColor(mWhereColor);
- holder.where.setTextColor(mWhereColor);
- if (selfAttendeeStatus == Attendees.ATTENDEE_STATUS_INVITED) {
- holder.colorChip.setDrawStyle(ColorChipView.DRAW_BORDER);
- } else {
- holder.colorChip.setDrawStyle(ColorChipView.DRAW_FULL);
- }
- }
-
- // Set the size of the color chip
- ViewGroup.LayoutParams params = holder.colorChip.getLayoutParams();
- if (allDay) {
- params.height = COLOR_CHIP_ALL_DAY_HEIGHT;
- } else {
- params.height = COLOR_CHIP_HEIGHT;
-
- }
- holder.colorChip.setLayoutParams(params);
-
- // Deal with exchange events that the owner cannot respond to
- int canRespond = cursor.getInt(AgendaWindowAdapter.INDEX_CAN_ORGANIZER_RESPOND);
- if (canRespond == 0) {
- String owner = cursor.getString(AgendaWindowAdapter.INDEX_OWNER_ACCOUNT);
- String organizer = cursor.getString(AgendaWindowAdapter.INDEX_ORGANIZER);
- if (owner.equals(organizer)) {
- holder.colorChip.setDrawStyle(ColorChipView.DRAW_FULL);
- holder.title.setTextColor(mStandardColor);
- holder.when.setTextColor(mStandardColor);
- holder.where.setTextColor(mStandardColor);
- }
- }
-
- TextView title = holder.title;
- TextView when = holder.when;
- TextView where = holder.where;
-
- holder.instanceId = cursor.getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID);
-
- /* Calendar Color */
- int color = Utils.getDisplayColorFromColor(cursor.getInt(AgendaWindowAdapter.INDEX_COLOR));
- holder.colorChip.setColor(color);
-
- // What
- String titleString = cursor.getString(AgendaWindowAdapter.INDEX_TITLE);
- if (titleString == null || titleString.length() == 0) {
- titleString = mNoTitleLabel;
- }
- title.setText(titleString);
-
- // When
- long begin = cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
- long end = cursor.getLong(AgendaWindowAdapter.INDEX_END);
- String eventTz = cursor.getString(AgendaWindowAdapter.INDEX_TIME_ZONE);
- int flags = 0;
- String whenString;
- // It's difficult to update all the adapters so just query this each
- // time we need to build the view.
- String tzString = Utils.getTimeZone(context, mTZUpdater);
- if (allDay) {
- tzString = Time.TIMEZONE_UTC;
- } else {
- flags = DateUtils.FORMAT_SHOW_TIME;
- }
- if (DateFormat.is24HourFormat(context)) {
- flags |= DateUtils.FORMAT_24HOUR;
- }
- mStringBuilder.setLength(0);
- whenString = DateUtils.formatDateRange(context, mFormatter, begin, end, flags, tzString)
- .toString();
- if (!allDay && !TextUtils.equals(tzString, eventTz)) {
- String displayName;
- // Figure out if this is in DST
- Time date = new Time(tzString);
- date.set(begin);
-
- TimeZone tz = TimeZone.getTimeZone(tzString);
- if (tz == null || tz.getID().equals("GMT")) {
- displayName = tzString;
- } else {
- displayName = tz.getDisplayName(date.isDst != 0, TimeZone.SHORT);
- }
- whenString += " (" + displayName + ")";
- }
- when.setText(whenString);
-
- /* Recurring event icon is removed
- String rrule = cursor.getString(AgendaWindowAdapter.INDEX_RRULE);
- if (!TextUtils.isEmpty(rrule)) {
- when.setCompoundDrawablesWithIntrinsicBounds(null, null,
- context.getResources().getDrawable(R.drawable.ic_repeat_dark), null);
- when.setCompoundDrawablePadding(5);
- } else {
- when.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
- } */
-
- /*
- // Repeating info
- View repeatContainer = view.findViewById(R.id.repeat_icon);
- String rrule = cursor.getString(AgendaWindowAdapter.INDEX_RRULE);
- if (!TextUtils.isEmpty(rrule)) {
- repeatContainer.setVisibility(View.VISIBLE);
- } else {
- repeatContainer.setVisibility(View.GONE);
- }
- */
-
- /*
- // Reminder
- boolean hasAlarm = cursor.getInt(AgendaWindowAdapter.INDEX_HAS_ALARM) != 0;
- if (hasAlarm) {
- updateReminder(view, context, begin, cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID));
- }
- */
-
- // Where
- String whereString = cursor.getString(AgendaWindowAdapter.INDEX_EVENT_LOCATION);
- if (whereString != null && whereString.length() > 0) {
- where.setVisibility(View.VISIBLE);
- where.setText(whereString);
- } else {
- where.setVisibility(View.GONE);
- }
- }
-
- /*
- public static void updateReminder(View view, Context context, long begin, long eventId) {
- ContentResolver cr = context.getContentResolver();
- Uri uri = Reminders.CONTENT_URI;
- String where = String.format(REMINDERS_WHERE, eventId);
-
- Cursor remindersCursor = cr.query(uri, REMINDERS_PROJECTION, where, null, null);
- if (remindersCursor != null) {
- LayoutInflater inflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- LinearLayout parent = (LinearLayout) view.findViewById(R.id.reminders_container);
- parent.removeAllViews();
- while (remindersCursor.moveToNext()) {
- int alarm = remindersCursor.getInt(REMINDERS_INDEX_MINUTES);
- String before = EditEvent.constructReminderLabel(context, alarm, true);
- LinearLayout reminderItem = (LinearLayout)
- inflater.inflate(R.layout.agenda_reminder_item, null);
- TextView reminderItemText = (TextView) reminderItem.findViewById(R.id.reminder);
- reminderItemText.setText(before);
- parent.addView(reminderItem);
- }
- }
- remindersCursor.close();
- }
- */
-}
-
diff --git a/src/com/android/calendar/agenda/AgendaByDayAdapter.java b/src/com/android/calendar/agenda/AgendaByDayAdapter.java
deleted file mode 100644
index 1f03740a..00000000
--- a/src/com/android/calendar/agenda/AgendaByDayAdapter.java
+++ /dev/null
@@ -1,684 +0,0 @@
-/*
- * Copyright (C) 2008 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.agenda;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.Typeface;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.TextView;
-
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-import com.android.calendar.agenda.AgendaWindowAdapter.DayAdapterInfo;
-
-import java.util.ArrayList;
-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;
- 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 mTmpTime;
- private String mTimeZone;
- // Note: Formatter is not thread safe. Fine for now as it is only used by the main thread.
- private final Formatter mFormatter;
- private final StringBuilder mStringBuilder;
-
- static class ViewHolder {
- TextView dayView;
- TextView dateView;
- int julianDay;
- boolean grayed;
- }
-
- private final Runnable mTZUpdater = new Runnable() {
- @Override
- public void run() {
- mTimeZone = Utils.getTimeZone(mContext, this);
- mTmpTime = new Time(mTimeZone);
- notifyDataSetChanged();
- }
- };
-
- public AgendaByDayAdapter(Context context) {
- mContext = context;
- 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());
- mTimeZone = Utils.getTimeZone(context, mTZUpdater);
- mTmpTime = new Time(mTimeZone);
- }
-
- public long getInstanceId(int position) {
- if (mRowInfo == null || position >= mRowInfo.size()) {
- return -1;
- }
- return mRowInfo.get(position).mInstanceId;
- }
-
- public long getStartTime(int position) {
- if (mRowInfo == null || position >= mRowInfo.size()) {
- return -1;
- }
- return mRowInfo.get(position).mEventStartTimeMilli;
- }
-
-
- // Returns the position of a header of a specific item
- public int getHeaderPosition(int position) {
- if (mRowInfo == null || position >= mRowInfo.size()) {
- return -1;
- }
-
- for (int i = position; i >=0; i --) {
- RowInfo row = mRowInfo.get(i);
- if (row != null && row.mType == TYPE_DAY)
- return i;
- }
- return -1;
- }
-
- // Returns the number of items in a section defined by a specific header location
- public int getHeaderItemsCount(int position) {
- if (mRowInfo == null) {
- return -1;
- }
- int count = 0;
- for (int i = position +1; i < mRowInfo.size(); i++) {
- if (mRowInfo.get(i).mType != TYPE_MEETING) {
- return count;
- }
- count ++;
- }
- return count;
- }
-
- @Override
- public int getCount() {
- if (mRowInfo != null) {
- return mRowInfo.size();
- }
- return mAgendaAdapter.getCount();
- }
-
- @Override
- public Object getItem(int position) {
- if (mRowInfo != null) {
- RowInfo row = mRowInfo.get(position);
- if (row.mType == TYPE_DAY) {
- return row;
- } else {
- return mAgendaAdapter.getItem(row.mPosition);
- }
- }
- return mAgendaAdapter.getItem(position);
- }
-
- @Override
- public long getItemId(int position) {
- if (mRowInfo != null) {
- RowInfo row = mRowInfo.get(position);
- if (row.mType == TYPE_DAY) {
- return -position;
- } else {
- return mAgendaAdapter.getItemId(row.mPosition);
- }
- }
- return mAgendaAdapter.getItemId(position);
- }
-
- @Override
- public int getViewTypeCount() {
- return TYPE_LAST;
- }
-
- @Override
- public int getItemViewType(int position) {
- return mRowInfo != null && mRowInfo.size() > position ?
- mRowInfo.get(position).mType : TYPE_DAY;
- }
-
- public boolean isDayHeaderView(int position) {
- return (getItemViewType(position) == TYPE_DAY);
- }
-
- @Override
- 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.
- return mAgendaAdapter.getView(position, convertView, parent);
- }
-
- RowInfo row = mRowInfo.get(position);
- if (row.mType == TYPE_DAY) {
- 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;
- holder.julianDay = row.mDay;
- }
- }
-
- 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.dayView = (TextView) agendaDayView.findViewById(R.id.day);
- holder.dateView = (TextView) agendaDayView.findViewById(R.id.date);
- holder.julianDay = row.mDay;
- holder.grayed = false;
- agendaDayView.setTag(holder);
- }
-
- // Re-use the member variable "mTime" which is set to the local
- // time zone.
- // It's difficult to find and update all these adapters when the
- // home tz changes so check it here and update if needed.
- String tz = Utils.getTimeZone(mContext, mTZUpdater);
- if (!TextUtils.equals(tz, mTmpTime.timezone)) {
- mTimeZone = tz;
- mTmpTime = new Time(tz);
- }
-
- // Build the text for the day of the week.
- // Should be yesterday/today/tomorrow (if applicable) + day of the week
-
- Time date = mTmpTime;
- long millis = date.setJulianDay(row.mDay);
- int flags = DateUtils.FORMAT_SHOW_WEEKDAY;
- mStringBuilder.setLength(0);
-
- String dayViewText = Utils.getDayOfWeekString(row.mDay, mTodayJulianDay, millis,
- mContext);
-
- // Build text for the date
- // Format should be month day
-
- mStringBuilder.setLength(0);
- flags = DateUtils.FORMAT_SHOW_DATE;
- String dateViewText = DateUtils.formatDateRange(mContext, mFormatter, millis, millis,
- flags, mTimeZone).toString();
-
- if (AgendaWindowAdapter.BASICLOG) {
- dayViewText += " P:" + position;
- dateViewText += " P:" + position;
- }
- holder.dayView.setText(dayViewText);
- holder.dateView.setText(dateViewText);
-
- // Set the background of the view, it is grayed for day that are in the past and today
- if (row.mDay > mTodayJulianDay) {
- agendaDayView.setBackgroundResource(R.drawable.agenda_item_bg_primary);
- holder.grayed = false;
- } else {
- agendaDayView.setBackgroundResource(R.drawable.agenda_item_bg_secondary);
- holder.grayed = true;
- }
- return agendaDayView;
- } else if (row.mType == TYPE_MEETING) {
- View itemView = mAgendaAdapter.getView(row.mPosition, convertView, parent);
- AgendaAdapter.ViewHolder holder = ((AgendaAdapter.ViewHolder) itemView.getTag());
- TextView title = holder.title;
- // The holder in the view stores information from the cursor, but the cursor has no
- // notion of multi-day event and the start time of each instance of a multi-day event
- // is the same. RowInfo has the correct info , so take it from there.
- holder.startTimeMilli = row.mEventStartTimeMilli;
- boolean allDay = holder.allDay;
- if (AgendaWindowAdapter.BASICLOG) {
- title.setText(title.getText() + " P:" + position);
- } else {
- title.setText(title.getText());
- }
-
- // if event in the past or started already, un-bold the title and set the background
- if ((!allDay && row.mEventStartTimeMilli <= System.currentTimeMillis()) ||
- (allDay && row.mDay <= mTodayJulianDay)) {
- itemView.setBackgroundResource(R.drawable.agenda_item_bg_secondary);
- title.setTypeface(Typeface.DEFAULT);
- holder.grayed = true;
- } else {
- itemView.setBackgroundResource(R.drawable.agenda_item_bg_primary);
- title.setTypeface(Typeface.DEFAULT_BOLD);
- holder.grayed = false;
- }
- holder.julianDay = row.mDay;
- return itemView;
- } else {
- // Error
- throw new IllegalStateException("Unknown event type:" + row.mType);
- }
- }
-
- public void clearDayHeaderInfo() {
- mRowInfo = null;
- }
-
- 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 tempTime = new Time(mTimeZone);
- long now = System.currentTimeMillis();
- tempTime.set(now);
- mTodayJulianDay = Time.getJulianDay(now, tempTime.gmtoff);
-
- LinkedList<MultipleDayInfo> multipleDayList = new LinkedList<MultipleDayInfo>();
- for (int position = 0; cursor.moveToNext(); position++) {
- int startDay = cursor.getInt(AgendaWindowAdapter.INDEX_START_DAY);
- long id = cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID);
- long startTime = cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
- long endTime = cursor.getLong(AgendaWindowAdapter.INDEX_END);
- long instanceId = cursor.getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID);
- boolean allDay = cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
- if (allDay) {
- startTime = Utils.convertAlldayUtcToLocal(tempTime, startTime, mTimeZone);
- endTime = Utils.convertAlldayUtcToLocal(tempTime, endTime, mTimeZone);
- }
- // Skip over the days outside of the adapter's range
- startDay = Math.max(startDay, dayAdapterInfo.start);
- // Make sure event's start time is not before the start of the day
- // (setJulianDay sets the time to 12:00am)
- long adapterStartTime = tempTime.setJulianDay(startDay);
- startTime = Math.max(startTime, adapterStartTime);
-
- if (startDay != prevStartDay) {
- // Check if we skipped over any empty days
- if (prevStartDay == -1) {
- rowInfo.add(new RowInfo(TYPE_DAY, startDay));
- } else {
- // If there are any multiple-day events that span the empty
- // range of days, then create day headers and events for
- // those multiple-day events.
- boolean dayHeaderAdded = false;
- for (int currentDay = prevStartDay + 1; currentDay <= startDay; currentDay++) {
- dayHeaderAdded = false;
- Iterator<MultipleDayInfo> iter = multipleDayList.iterator();
- while (iter.hasNext()) {
- MultipleDayInfo info = iter.next();
- // If this event has ended then remove it from the
- // list.
- if (info.mEndDay < currentDay) {
- iter.remove();
- continue;
- }
-
- // If this is the first event for the day, then
- // insert a day header.
- if (!dayHeaderAdded) {
- rowInfo.add(new RowInfo(TYPE_DAY, currentDay));
- dayHeaderAdded = true;
- }
- long nextMidnight = Utils.getNextMidnight(tempTime,
- info.mEventStartTimeMilli, mTimeZone);
-
- long infoEndTime = (info.mEndDay == currentDay) ?
- info.mEventEndTimeMilli : nextMidnight;
- rowInfo.add(new RowInfo(TYPE_MEETING, currentDay, info.mPosition,
- info.mEventId, info.mEventStartTimeMilli,
- infoEndTime, info.mInstanceId, info.mAllDay));
-
- info.mEventStartTimeMilli = nextMidnight;
- }
- }
-
- // If the day header was not added for the start day, then
- // add it now.
- if (!dayHeaderAdded) {
- rowInfo.add(new RowInfo(TYPE_DAY, startDay));
- }
- }
- prevStartDay = startDay;
- }
-
- // If this event spans multiple days, then add it to the multipleDay
- // list.
- 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) {
- long nextMidnight = Utils.getNextMidnight(tempTime, startTime, mTimeZone);
- multipleDayList.add(new MultipleDayInfo(position, endDay, id, nextMidnight,
- endTime, instanceId, allDay));
- // Add in the event for this cursor position - since it is the start of a multi-day
- // event, the end time is midnight
- rowInfo.add(new RowInfo(TYPE_MEETING, startDay, position, id, startTime,
- nextMidnight, instanceId, allDay));
- } else {
- // Add in the event for this cursor position
- rowInfo.add(new RowInfo(TYPE_MEETING, startDay, position, id, startTime, endTime,
- instanceId, allDay));
- }
- }
-
- // 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) {
- for (int currentDay = prevStartDay + 1; currentDay <= dayAdapterInfo.end;
- currentDay++) {
- boolean dayHeaderAdded = false;
- Iterator<MultipleDayInfo> iter = multipleDayList.iterator();
- while (iter.hasNext()) {
- MultipleDayInfo info = iter.next();
- // If this event has ended then remove it from the
- // list.
- if (info.mEndDay < currentDay) {
- iter.remove();
- continue;
- }
-
- // If this is the first event for the day, then
- // insert a day header.
- if (!dayHeaderAdded) {
- rowInfo.add(new RowInfo(TYPE_DAY, currentDay));
- dayHeaderAdded = true;
- }
- long nextMidnight = Utils.getNextMidnight(tempTime, info.mEventStartTimeMilli,
- mTimeZone);
- long infoEndTime =
- (info.mEndDay == currentDay) ? info.mEventEndTimeMilli : nextMidnight;
- rowInfo.add(new RowInfo(TYPE_MEETING, currentDay, info.mPosition,
- info.mEventId, info.mEventStartTimeMilli, infoEndTime,
- info.mInstanceId, info.mAllDay));
-
- info.mEventStartTimeMilli = nextMidnight;
- }
- }
- }
- mRowInfo = rowInfo;
- }
-
- private static class RowInfo {
- // mType is either a day header (TYPE_DAY) or an event (TYPE_MEETING)
- final int mType;
-
- final int mDay; // Julian day
- final int mPosition; // cursor position (not used for TYPE_DAY)
- // This is used to mark a day header as the first day with events that is "today"
- // or later. This flag is used by the adapter to create a view with a visual separator
- // between the past and the present/future
- boolean mFirstDayAfterYesterday;
- final long mEventId;
- final long mEventStartTimeMilli;
- final long mEventEndTimeMilli;
- final long mInstanceId;
- final boolean mAllDay;
-
- RowInfo(int type, int julianDay, int position, long id, long startTime, long endTime,
- long instanceId, boolean allDay) {
- mType = type;
- mDay = julianDay;
- mPosition = position;
- mEventId = id;
- mEventStartTimeMilli = startTime;
- mEventEndTimeMilli = endTime;
- mFirstDayAfterYesterday = false;
- mInstanceId = instanceId;
- mAllDay = allDay;
- }
-
- RowInfo(int type, int julianDay) {
- mType = type;
- mDay = julianDay;
- mPosition = 0;
- mEventId = 0;
- mEventStartTimeMilli = 0;
- mEventEndTimeMilli = 0;
- mFirstDayAfterYesterday = false;
- mInstanceId = -1;
- mAllDay = false;
- }
- }
-
- private static class MultipleDayInfo {
- final int mPosition;
- final int mEndDay;
- final long mEventId;
- long mEventStartTimeMilli;
- long mEventEndTimeMilli;
- final long mInstanceId;
- final boolean mAllDay;
-
- MultipleDayInfo(int position, int endDay, long id, long startTime, long endTime,
- long instanceId, boolean allDay) {
- mPosition = position;
- mEndDay = endDay;
- mEventId = id;
- mEventStartTimeMilli = startTime;
- mEventEndTimeMilli = endTime;
- mInstanceId = instanceId;
- mAllDay = allDay;
- }
- }
-
- /**
- * Finds the position in the cursor of the event that best matches the time and Id.
- * It will try to find the event that has the specified id and start time, if such event
- * doesn't exist, it will return the event with a matching id that is closest to the start time.
- * If the id doesn't exist, it will return the event with start time closest to the specified
- * time.
- * @param time - start of event in milliseconds (or any arbitrary time if event id is unknown)
- * @param id - Event id (-1 if unknown).
- * @return Position of event (if found) or position of nearest event according to the time.
- * Zero if no event found
- */
- public int findEventPositionNearestTime(Time time, long id) {
- if (mRowInfo == null) {
- return 0;
- }
- long millis = time.toMillis(false /* use isDst */);
- long minDistance = Integer.MAX_VALUE; // some big number
- long idFoundMinDistance = Integer.MAX_VALUE; // some big number
- int minIndex = 0;
- int idFoundMinIndex = 0;
- int eventInTimeIndex = -1;
- int allDayEventInTimeIndex = -1;
- int allDayEventDay = 0;
- int minDay = 0;
- boolean idFound = false;
- int len = mRowInfo.size();
-
- // Loop through the events and find the best match
- // 1. Event id and start time matches requested id and time
- // 2. Event id matches and closest time
- // 3. No event id match , time matches a all day event (midnight)
- // 4. No event id match , time is between event start and end
- // 5. No event id match , all day event
- // 6. The closest event to the requested time
-
- for (int index = 0; index < len; index++) {
- RowInfo row = mRowInfo.get(index);
- if (row.mType == TYPE_DAY) {
- continue;
- }
-
- // Found exact match - done
- if (row.mEventId == id) {
- if (row.mEventStartTimeMilli == millis) {
- return index;
- }
-
- // Not an exact match, Save event index if it is the closest to time so far
- long distance = Math.abs(millis - row.mEventStartTimeMilli);
- if (distance < idFoundMinDistance) {
- idFoundMinDistance = distance;
- idFoundMinIndex = index;
- }
- idFound = true;
- }
- if (!idFound) {
- // Found an event that contains the requested time
- if (millis >= row.mEventStartTimeMilli && millis <= row.mEventEndTimeMilli) {
- if (row.mAllDay) {
- if (allDayEventInTimeIndex == -1) {
- allDayEventInTimeIndex = index;
- allDayEventDay = row.mDay;
- }
- } else if (eventInTimeIndex == -1){
- eventInTimeIndex = index;
- }
- } else if (eventInTimeIndex == -1){
- // Save event index if it is the closest to time so far
- long distance = Math.abs(millis - row.mEventStartTimeMilli);
- if (distance < minDistance) {
- minDistance = distance;
- minIndex = index;
- minDay = row.mDay;
- }
- }
- }
- }
- // We didn't find an exact match so take the best matching event
- // Closest event with the same id
- if (idFound) {
- return idFoundMinIndex;
- }
- // Event which occurs at the searched time
- if (eventInTimeIndex != -1) {
- return eventInTimeIndex;
- // All day event which occurs at the same day of the searched time as long as there is
- // no regular event at the same day
- } else if (allDayEventInTimeIndex != -1 && minDay != allDayEventDay) {
- return allDayEventInTimeIndex;
- }
- // Closest event
- return minIndex;
- }
-
-
- /**
- * Returns a flag indicating if this position is the first day after "yesterday" that has
- * events in it.
- *
- * @return a flag indicating if this is the "first day after yesterday"
- */
- public boolean isFirstDayAfterYesterday(int position) {
- int headerPos = getHeaderPosition(position);
- RowInfo row = mRowInfo.get(headerPos);
- if (row != null) {
- return row.mFirstDayAfterYesterday;
- }
- return false;
- }
-
- /**
- * Finds the Julian day containing the event at the given position.
- *
- * @param position the list position of an event
- * @return the Julian day containing that event
- */
- public int findJulianDayFromPosition(int position) {
- if (mRowInfo == null || position < 0) {
- return 0;
- }
-
- int len = mRowInfo.size();
- if (position >= len) return 0; // no row info at this position
-
- for (int index = position; index >= 0; index--) {
- RowInfo row = mRowInfo.get(index);
- if (row.mType == TYPE_DAY) {
- return row.mDay;
- }
- }
- return 0;
- }
-
- /**
- * Marks the current row as the first day that has events after "yesterday".
- * Used to mark the separation between the past and the present/future
- *
- * @param position in the adapter
- */
- public void setAsFirstDayAfterYesterday(int position) {
- if (mRowInfo == null || position < 0 || position > mRowInfo.size()) {
- return;
- }
- RowInfo row = mRowInfo.get(position);
- row.mFirstDayAfterYesterday = true;
- }
-
- /**
- * Converts a list position to a cursor position. The list contains
- * day headers as well as events. The cursor contains only events.
- *
- * @param listPos the list position of an event
- * @return the corresponding cursor position of that event
- * if the position point to day header , it will give the position of the next event
- * negated.
- */
- public int getCursorPosition(int listPos) {
- if (mRowInfo != null && listPos >= 0) {
- RowInfo row = mRowInfo.get(listPos);
- if (row.mType == TYPE_MEETING) {
- return row.mPosition;
- } else {
- int nextPos = listPos + 1;
- if (nextPos < mRowInfo.size()) {
- nextPos = getCursorPosition(nextPos);
- if (nextPos >= 0) {
- return -nextPos;
- }
- }
- }
- }
- return Integer.MIN_VALUE;
- }
-
- @Override
- public boolean areAllItemsEnabled() {
- return false;
- }
-
- @Override
- public boolean isEnabled(int position) {
- if (mRowInfo != null && position < mRowInfo.size()) {
- RowInfo row = mRowInfo.get(position);
- return row.mType == TYPE_MEETING;
- }
- return true;
- }
-}
diff --git a/src/com/android/calendar/agenda/AgendaFragment.java b/src/com/android/calendar/agenda/AgendaFragment.java
deleted file mode 100644
index ff5c47cc..00000000
--- a/src/com/android/calendar/agenda/AgendaFragment.java
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * 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.agenda;
-
-
-import android.app.Activity;
-import android.app.Fragment;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.provider.CalendarContract.Attendees;
-import android.text.format.Time;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AbsListView;
-import android.widget.AbsListView.OnScrollListener;
-import android.widget.Adapter;
-import android.widget.HeaderViewListAdapter;
-
-import com.android.calendar.CalendarController;
-import com.android.calendar.CalendarController.EventInfo;
-import com.android.calendar.CalendarController.EventType;
-import com.android.calendar.CalendarController.ViewType;
-import com.android.calendar.EventInfoFragment;
-import com.android.calendar.GeneralPreferences;
-import com.android.calendar.R;
-import com.android.calendar.StickyHeaderListView;
-import com.android.calendar.Utils;
-
-import java.util.Date;
-
-public class AgendaFragment extends Fragment implements CalendarController.EventHandler,
- OnScrollListener {
-
- private static final String TAG = AgendaFragment.class.getSimpleName();
- private static boolean DEBUG = false;
-
- protected static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time";
- protected static final String BUNDLE_KEY_RESTORE_INSTANCE_ID = "key_restore_instance_id";
-
- private AgendaListView mAgendaListView;
- private Activity mActivity;
- private final Time mTime;
- private String mTimeZone;
- private final long mInitialTimeMillis;
- private boolean mShowEventDetailsWithAgenda;
- private CalendarController mController;
- private EventInfoFragment mEventFragment;
- private String mQuery;
- private boolean mUsedForSearch = false;
- private boolean mIsTabletConfig;
- private EventInfo mOnAttachedInfo = null;
- private boolean mOnAttachAllDay = false;
- private AgendaWindowAdapter mAdapter = null;
- private boolean mForceReplace = true;
- private long mLastShownEventId = -1;
-
-
-
- // Tracks the time of the top visible view in order to send UPDATE_TITLE messages to the action
- // bar.
- int mJulianDayOnTop = -1;
-
- private final Runnable mTZUpdater = new Runnable() {
- @Override
- public void run() {
- mTimeZone = Utils.getTimeZone(getActivity(), this);
- mTime.switchTimezone(mTimeZone);
- }
- };
-
- public AgendaFragment() {
- this(0, false);
- }
-
-
- // timeMillis - time of first event to show
- // usedForSearch - indicates if this fragment is used in the search fragment
- public AgendaFragment(long timeMillis, boolean usedForSearch) {
- mInitialTimeMillis = timeMillis;
- mTime = new Time();
- mLastHandledEventTime = new Time();
-
- if (mInitialTimeMillis == 0) {
- mTime.setToNow();
- } else {
- mTime.set(mInitialTimeMillis);
- }
- mLastHandledEventTime.set(mTime);
- mUsedForSearch = usedForSearch;
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- mTimeZone = Utils.getTimeZone(activity, mTZUpdater);
- mTime.switchTimezone(mTimeZone);
- mActivity = activity;
- if (mOnAttachedInfo != null) {
- showEventInfo(mOnAttachedInfo, mOnAttachAllDay, true);
- mOnAttachedInfo = null;
- }
- }
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- mController = CalendarController.getInstance(mActivity);
- mShowEventDetailsWithAgenda =
- Utils.getConfigBool(mActivity, R.bool.show_event_details_with_agenda);
- mIsTabletConfig =
- Utils.getConfigBool(mActivity, R.bool.tablet_config);
- if (icicle != null) {
- long prevTime = icicle.getLong(BUNDLE_KEY_RESTORE_TIME, -1);
- if (prevTime != -1) {
- mTime.set(prevTime);
- if (DEBUG) {
- Log.d(TAG, "Restoring time to " + mTime.toString());
- }
- }
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
-
-
- int screenWidth = mActivity.getResources().getDisplayMetrics().widthPixels;
- View v = inflater.inflate(R.layout.agenda_fragment, null);
-
- mAgendaListView = (AgendaListView)v.findViewById(R.id.agenda_events_list);
- mAgendaListView.setClickable(true);
-
- if (savedInstanceState != null) {
- long instanceId = savedInstanceState.getLong(BUNDLE_KEY_RESTORE_INSTANCE_ID, -1);
- if (instanceId != -1) {
- mAgendaListView.setSelectedInstanceId(instanceId);
- }
- }
-
- View eventView = v.findViewById(R.id.agenda_event_info);
- if (!mShowEventDetailsWithAgenda) {
- eventView.setVisibility(View.GONE);
- }
-
- View topListView;
- // Set adapter & HeaderIndexer for StickyHeaderListView
- StickyHeaderListView lv =
- (StickyHeaderListView)v.findViewById(R.id.agenda_sticky_header_list);
- if (lv != null) {
- Adapter a = mAgendaListView.getAdapter();
- lv.setAdapter(a);
- if (a instanceof HeaderViewListAdapter) {
- mAdapter = (AgendaWindowAdapter) ((HeaderViewListAdapter)a).getWrappedAdapter();
- lv.setIndexer(mAdapter);
- lv.setHeaderHeightListener(mAdapter);
- } else if (a instanceof AgendaWindowAdapter) {
- mAdapter = (AgendaWindowAdapter)a;
- lv.setIndexer(mAdapter);
- lv.setHeaderHeightListener(mAdapter);
- } else {
- Log.wtf(TAG, "Cannot find HeaderIndexer for StickyHeaderListView");
- }
-
- // Set scroll listener so that the date on the ActionBar can be set while
- // the user scrolls the view
- lv.setOnScrollListener(this);
- lv.setHeaderSeparator(getResources().getColor(R.color.agenda_list_separator_color), 1);
- topListView = lv;
- } else {
- topListView = mAgendaListView;
- }
-
- // Since using weight for sizing the two panes of the agenda fragment causes the whole
- // fragment to re-measure when the sticky header is replaced, calculate the weighted
- // size of each pane here and set it
-
- if (!mShowEventDetailsWithAgenda) {
- ViewGroup.LayoutParams params = topListView.getLayoutParams();
- params.width = screenWidth;
- topListView.setLayoutParams(params);
- } else {
- ViewGroup.LayoutParams listParams = topListView.getLayoutParams();
- listParams.width = screenWidth * 4 / 10;
- topListView.setLayoutParams(listParams);
- ViewGroup.LayoutParams detailsParams = eventView.getLayoutParams();
- detailsParams.width = screenWidth - listParams.width;
- eventView.setLayoutParams(detailsParams);
- }
- return v;
- }
-
- @Override
- public void onResume() {
- super.onResume();
- if (DEBUG) {
- Log.v(TAG, "OnResume to " + mTime.toString());
- }
-
- SharedPreferences prefs = GeneralPreferences.getSharedPreferences(
- getActivity());
- boolean hideDeclined = prefs.getBoolean(
- GeneralPreferences.KEY_HIDE_DECLINED, false);
-
- mAgendaListView.setHideDeclinedEvents(hideDeclined);
- if (mLastHandledEventId != -1) {
- mAgendaListView.goTo(mLastHandledEventTime, mLastHandledEventId, mQuery, true, false);
- mLastHandledEventTime = null;
- mLastHandledEventId = -1;
- } else {
- mAgendaListView.goTo(mTime, -1, mQuery, true, false);
- }
- mAgendaListView.onResume();
-
-// // Register for Intent broadcasts
-// IntentFilter filter = new IntentFilter();
-// filter.addAction(Intent.ACTION_TIME_CHANGED);
-// filter.addAction(Intent.ACTION_DATE_CHANGED);
-// filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
-// registerReceiver(mIntentReceiver, filter);
-//
-// mContentResolver.registerContentObserver(Events.CONTENT_URI, true, mObserver);
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- if (mAgendaListView == null) {
- return;
- }
- if (mShowEventDetailsWithAgenda) {
- long timeToSave;
- if (mLastHandledEventTime != null) {
- timeToSave = mLastHandledEventTime.toMillis(true);
- mTime.set(mLastHandledEventTime);
- } else {
- timeToSave = System.currentTimeMillis();
- mTime.set(timeToSave);
- }
- outState.putLong(BUNDLE_KEY_RESTORE_TIME, timeToSave);
- mController.setTime(timeToSave);
- } else {
- AgendaWindowAdapter.AgendaItem item = mAgendaListView.getFirstVisibleAgendaItem();
- if (item != null) {
- long firstVisibleTime = mAgendaListView.getFirstVisibleTime(item);
- if (firstVisibleTime > 0) {
- mTime.set(firstVisibleTime);
- mController.setTime(firstVisibleTime);
- outState.putLong(BUNDLE_KEY_RESTORE_TIME, firstVisibleTime);
- }
- // Tell AllInOne the event id of the first visible event in the list. The id will be
- // used in the GOTO when AllInOne is restored so that Agenda Fragment can select a
- // specific event and not just the time.
- mLastShownEventId = item.id;
- }
- }
- if (DEBUG) {
- Log.v(TAG, "onSaveInstanceState " + mTime.toString());
- }
-
- long selectedInstance = mAgendaListView.getSelectedInstanceId();
- if (selectedInstance >= 0) {
- outState.putLong(BUNDLE_KEY_RESTORE_INSTANCE_ID, selectedInstance);
- }
- }
-
- /**
- * This cleans up the event info fragment since the FragmentManager doesn't
- * handle nested fragments. Without this, the action bar buttons added by
- * the info fragment can come back on a rotation.
- *
- * @param fragmentManager
- */
- public void removeFragments(FragmentManager fragmentManager) {
- if (getActivity().isFinishing()) {
- return;
- }
- FragmentTransaction ft = fragmentManager.beginTransaction();
- Fragment f = fragmentManager.findFragmentById(R.id.agenda_event_info);
- if (f != null) {
- ft.remove(f);
- }
- ft.commit();
- }
-
- @Override
- public void onPause() {
- super.onPause();
-
- mAgendaListView.onPause();
-
-// mContentResolver.unregisterContentObserver(mObserver);
-// unregisterReceiver(mIntentReceiver);
-
- // Record Agenda View as the (new) default detailed view.
-// Utils.setDefaultView(this, CalendarApplication.AGENDA_VIEW_ID);
- }
-
- private void goTo(EventInfo event, boolean animate) {
- if (event.selectedTime != null) {
- mTime.set(event.selectedTime);
- } else if (event.startTime != null) {
- mTime.set(event.startTime);
- }
- if (mAgendaListView == null) {
- // The view hasn't been set yet. Just save the time and use it
- // later.
- return;
- }
- mAgendaListView.goTo(mTime, event.id, mQuery, false,
- ((event.extraLong & CalendarController.EXTRA_GOTO_TODAY) != 0 &&
- mShowEventDetailsWithAgenda) ? true : false);
- AgendaAdapter.ViewHolder vh = mAgendaListView.getSelectedViewHolder();
- // Make sure that on the first time the event info is shown to recreate it
- Log.d(TAG, "selected viewholder is null: " + (vh == null));
- showEventInfo(event, vh != null ? vh.allDay : false, mForceReplace);
- mForceReplace = false;
- }
-
- private void search(String query, Time time) {
- mQuery = query;
- if (time != null) {
- mTime.set(time);
- }
- if (mAgendaListView == null) {
- // The view hasn't been set yet. Just return.
- return;
- }
- mAgendaListView.goTo(time, -1, mQuery, true, false);
- }
-
- @Override
- public void eventsChanged() {
- if (mAgendaListView != null) {
- mAgendaListView.refresh(true);
- }
- }
-
- @Override
- public long getSupportedEventTypes() {
- return EventType.GO_TO | EventType.EVENTS_CHANGED | ((mUsedForSearch)?EventType.SEARCH:0);
- }
-
- private long mLastHandledEventId = -1;
- private Time mLastHandledEventTime = null;
- @Override
- public void handleEvent(EventInfo event) {
- if (event.eventType == EventType.GO_TO) {
- // TODO support a range of time
- // TODO support event_id
- // TODO figure out the animate bit
- mLastHandledEventId = event.id;
- mLastHandledEventTime =
- (event.selectedTime != null) ? event.selectedTime : event.startTime;
- goTo(event, true);
- } else if (event.eventType == EventType.SEARCH) {
- search(event.query, event.startTime);
- } else if (event.eventType == EventType.EVENTS_CHANGED) {
- eventsChanged();
- }
- }
-
- public long getLastShowEventId() {
- return mLastShownEventId;
- }
-
- // Shows the selected event in the Agenda view
- private void showEventInfo(EventInfo event, boolean allDay, boolean replaceFragment) {
-
- // Ignore unknown events
- if (event.id == -1) {
- Log.e(TAG, "showEventInfo, event ID = " + event.id);
- return;
- }
-
- mLastShownEventId = event.id;
-
- // Create a fragment to show the event to the side of the agenda list
- if (mShowEventDetailsWithAgenda) {
- FragmentManager fragmentManager = getFragmentManager();
- if (fragmentManager == null) {
- // Got a goto event before the fragment finished attaching,
- // stash the event and handle it later.
- mOnAttachedInfo = event;
- mOnAttachAllDay = allDay;
- return;
- }
- FragmentTransaction ft = fragmentManager.beginTransaction();
-
- if (allDay) {
- event.startTime.timezone = Time.TIMEZONE_UTC;
- event.endTime.timezone = Time.TIMEZONE_UTC;
- }
-
- if (DEBUG) {
- Log.d(TAG, "***");
- Log.d(TAG, "showEventInfo: start: " + new Date(event.startTime.toMillis(true)));
- Log.d(TAG, "showEventInfo: end: " + new Date(event.endTime.toMillis(true)));
- Log.d(TAG, "showEventInfo: all day: " + allDay);
- Log.d(TAG, "***");
- }
-
- long startMillis = event.startTime.toMillis(true);
- long endMillis = event.endTime.toMillis(true);
- EventInfoFragment fOld =
- (EventInfoFragment)fragmentManager.findFragmentById(R.id.agenda_event_info);
- if (fOld == null || replaceFragment || fOld.getStartMillis() != startMillis ||
- fOld.getEndMillis() != endMillis || fOld.getEventId() != event.id) {
- mEventFragment = new EventInfoFragment(mActivity, event.id,
- startMillis, endMillis,
- Attendees.ATTENDEE_STATUS_NONE, false,
- EventInfoFragment.DIALOG_WINDOW_STYLE, null);
- ft.replace(R.id.agenda_event_info, mEventFragment);
- ft.commit();
- } else {
- fOld.reloadEvents();
- }
- }
- }
-
- // OnScrollListener implementation to update the date on the pull-down menu of the app
-
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- // Save scroll state so that the adapter can stop the scroll when the
- // agenda list is fling state and it needs to set the agenda list to a new position
- if (mAdapter != null) {
- mAdapter.setScrollState(scrollState);
- }
- }
-
- // Gets the time of the first visible view. If it is a new time, send a message to update
- // the time on the ActionBar
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
- int totalItemCount) {
- int julianDay = mAgendaListView.getJulianDayFromPosition(firstVisibleItem
- - mAgendaListView.getHeaderViewsCount());
- // On error - leave the old view
- if (julianDay == 0) {
- return;
- }
- // If the day changed, update the ActionBar
- if (mJulianDayOnTop != julianDay) {
- mJulianDayOnTop = julianDay;
- Time t = new Time(mTimeZone);
- t.setJulianDay(mJulianDayOnTop);
- mController.setTime(t.toMillis(true));
- // Cannot sent a message that eventually may change the layout of the views
- // so instead post a runnable that will run when the layout is done
- if (!mIsTabletConfig) {
- view.post(new Runnable() {
- @Override
- public void run() {
- Time t = new Time(mTimeZone);
- t.setJulianDay(mJulianDayOnTop);
- mController.sendEvent(this, EventType.UPDATE_TITLE, t, t, null, -1,
- ViewType.CURRENT, 0, null, null);
- }
- });
- }
- }
- }
-}
diff --git a/src/com/android/calendar/agenda/AgendaListView.java b/src/com/android/calendar/agenda/AgendaListView.java
deleted file mode 100644
index 6cfc7e5b..00000000
--- a/src/com/android/calendar/agenda/AgendaListView.java
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * 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.agenda;
-
-import com.android.calendar.CalendarController;
-import com.android.calendar.CalendarController.EventType;
-import com.android.calendar.DeleteEventHelper;
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-import com.android.calendar.agenda.AgendaAdapter.ViewHolder;
-import com.android.calendar.agenda.AgendaWindowAdapter.DayAdapterInfo;
-import com.android.calendar.agenda.AgendaWindowAdapter.AgendaItem;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.provider.CalendarContract.Attendees;
-import android.text.format.Time;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ListView;
-import android.widget.TextView;
-
-public class AgendaListView extends ListView implements OnItemClickListener {
-
- private static final String TAG = "AgendaListView";
- private static final boolean DEBUG = false;
- private static final int EVENT_UPDATE_TIME = 300000; // 5 minutes
-
- private AgendaWindowAdapter mWindowAdapter;
- private DeleteEventHelper mDeleteEventHelper;
- private Context mContext;
- private String mTimeZone;
- private Time mTime;
- private boolean mShowEventDetailsWithAgenda;
- private Handler mHandler = null;
-
- private final Runnable mTZUpdater = new Runnable() {
- @Override
- public void run() {
- mTimeZone = Utils.getTimeZone(mContext, this);
- mTime.switchTimezone(mTimeZone);
- }
- };
-
- // runs every midnight and refreshes the view in order to update the past/present
- // separator
- private final Runnable mMidnightUpdater = new Runnable() {
- @Override
- public void run() {
- refresh(true);
- Utils.setMidnightUpdater(mHandler, mMidnightUpdater, mTimeZone);
- }
- };
-
- // Runs every EVENT_UPDATE_TIME to gray out past events
- private final Runnable mPastEventUpdater = new Runnable() {
- @Override
- public void run() {
- if (updatePastEvents() == true) {
- refresh(true);
- }
- setPastEventsUpdater();
- }
- };
-
- public AgendaListView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initView(context);
- }
-
- private void initView(Context context) {
- mContext = context;
- mTimeZone = Utils.getTimeZone(context, mTZUpdater);
- mTime = new Time(mTimeZone);
- setOnItemClickListener(this);
- setVerticalScrollBarEnabled(false);
- mWindowAdapter = new AgendaWindowAdapter(context, this,
- Utils.getConfigBool(context, R.bool.show_event_details_with_agenda));
- mWindowAdapter.setSelectedInstanceId(-1/* TODO:instanceId */);
- setAdapter(mWindowAdapter);
- setCacheColorHint(context.getResources().getColor(R.color.agenda_item_not_selected));
- mDeleteEventHelper =
- new DeleteEventHelper(context, null, false /* don't exit when done */);
- mShowEventDetailsWithAgenda = Utils.getConfigBool(mContext,
- R.bool.show_event_details_with_agenda);
- // Hide ListView dividers, they are done in the item views themselves
- setDivider(null);
- setDividerHeight(0);
-
- mHandler = new Handler();
- }
-
- // Sets a thread to run every EVENT_UPDATE_TIME in order to update the list
- // with grayed out past events
- private void setPastEventsUpdater() {
-
- // Run the thread in the nearest rounded EVENT_UPDATE_TIME
- long now = System.currentTimeMillis();
- long roundedTime = (now / EVENT_UPDATE_TIME) * EVENT_UPDATE_TIME;
- mHandler.removeCallbacks(mPastEventUpdater);
- mHandler.postDelayed(mPastEventUpdater, EVENT_UPDATE_TIME - (now - roundedTime));
- }
-
- // Stop the past events thread
- private void resetPastEventsUpdater() {
- mHandler.removeCallbacks(mPastEventUpdater);
- }
-
- // Go over all visible views and checks if all past events are grayed out.
- // Returns true is there is at least one event that ended and it is not
- // grayed out.
- private boolean updatePastEvents() {
-
- int childCount = getChildCount();
- boolean needUpdate = false;
- long now = System.currentTimeMillis();
- Time time = new Time(mTimeZone);
- time.set(now);
- int todayJulianDay = Time.getJulianDay(now, time.gmtoff);
-
- // Go over views in list
- for (int i = 0; i < childCount; ++i) {
- View listItem = getChildAt(i);
- Object o = listItem.getTag();
- if (o instanceof AgendaByDayAdapter.ViewHolder) {
- // day view - check if day in the past and not grayed yet
- AgendaByDayAdapter.ViewHolder holder = (AgendaByDayAdapter.ViewHolder) o;
- if (holder.julianDay <= todayJulianDay && !holder.grayed) {
- needUpdate = true;
- break;
- }
- } else if (o instanceof AgendaAdapter.ViewHolder) {
- // meeting view - check if event in the past or started already and not grayed yet
- // All day meetings for a day are grayed out
- AgendaAdapter.ViewHolder holder = (AgendaAdapter.ViewHolder) o;
- if (!holder.grayed && ((!holder.allDay && holder.startTimeMilli <= now) ||
- (holder.allDay && holder.julianDay <= todayJulianDay))) {
- needUpdate = true;
- break;
- }
- }
- }
- return needUpdate;
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mWindowAdapter.close();
- }
-
- // Implementation of the interface OnItemClickListener
- @Override
- public void onItemClick(AdapterView<?> a, View v, int position, long id) {
- if (id != -1) {
- // Switch to the EventInfo view
- AgendaItem item = mWindowAdapter.getAgendaItemByPosition(position);
- long oldInstanceId = mWindowAdapter.getSelectedInstanceId();
- mWindowAdapter.setSelectedView(v);
-
- // If events are shown to the side of the agenda list , do nothing
- // when the same event is selected , otherwise show the selected event.
-
- if (item != null && (oldInstanceId != mWindowAdapter.getSelectedInstanceId() ||
- !mShowEventDetailsWithAgenda)) {
- long startTime = item.begin;
- long endTime = item.end;
- // Holder in view holds the start of the specific part of a multi-day event ,
- // use it for the goto
- long holderStartTime;
- Object holder = v.getTag();
- if (holder instanceof AgendaAdapter.ViewHolder) {
- holderStartTime = ((AgendaAdapter.ViewHolder) holder).startTimeMilli;
- } else {
- holderStartTime = startTime;
- }
- if (item.allDay) {
- startTime = Utils.convertAlldayLocalToUTC(mTime, startTime, mTimeZone);
- endTime = Utils.convertAlldayLocalToUTC(mTime, endTime, mTimeZone);
- }
- mTime.set(startTime);
- CalendarController controller = CalendarController.getInstance(mContext);
- controller.sendEventRelatedEventWithExtra(this, EventType.VIEW_EVENT, item.id,
- startTime, endTime, 0, 0, CalendarController.EventInfo.buildViewExtraLong(
- Attendees.ATTENDEE_STATUS_NONE, item.allDay), holderStartTime);
- }
- }
- }
-
- public void goTo(Time time, long id, String searchQuery, boolean forced,
- boolean refreshEventInfo) {
- if (time == null) {
- time = mTime;
- long goToTime = getFirstVisibleTime(null);
- if (goToTime <= 0) {
- goToTime = System.currentTimeMillis();
- }
- time.set(goToTime);
- }
- mTime.set(time);
- mTime.switchTimezone(mTimeZone);
- mTime.normalize(true);
- if (DEBUG) {
- Log.d(TAG, "Goto with time " + mTime.toString());
- }
- mWindowAdapter.refresh(mTime, id, searchQuery, forced, refreshEventInfo);
- }
-
- public void refresh(boolean forced) {
- mWindowAdapter.refresh(mTime, -1, null, forced, false);
- }
-
- public void deleteSelectedEvent() {
- int position = getSelectedItemPosition();
- AgendaItem agendaItem = mWindowAdapter.getAgendaItemByPosition(position);
- if (agendaItem != null) {
- mDeleteEventHelper.delete(agendaItem.begin, agendaItem.end, agendaItem.id, -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) {
- AgendaItem item = mWindowAdapter.getAgendaItemByPosition(position);
- if (item != null) {
- return item.begin;
- }
- }
- return getFirstVisibleTime(null);
- }
-
- public AgendaAdapter.ViewHolder getSelectedViewHolder() {
- return mWindowAdapter.getSelectedViewHolder();
- }
-
- public long getFirstVisibleTime(AgendaItem item) {
- AgendaItem agendaItem = item;
- if (item == null) {
- agendaItem = getFirstVisibleAgendaItem();
- }
- if (agendaItem != null) {
- Time t = new Time(mTimeZone);
- t.set(agendaItem.begin);
- // Save and restore the time since setJulianDay sets the time to 00:00:00
- int hour = t.hour;
- int minute = t.minute;
- int second = t.second;
- t.setJulianDay(agendaItem.startDay);
- t.hour = hour;
- t.minute = minute;
- t.second = second;
- if (DEBUG) {
- t.normalize(true);
- Log.d(TAG, "first position had time " + t.toString());
- }
- return t.normalize(false);
- }
- return 0;
- }
-
- public AgendaItem getFirstVisibleAgendaItem() {
- int position = getFirstVisiblePosition();
- if (DEBUG) {
- Log.v(TAG, "getFirstVisiblePosition = " + position);
- }
-
- // mShowEventDetailsWithAgenda == true implies we have a sticky header. In that case
- // we may need to take the second visible position, since the first one maybe the one
- // under the sticky header.
- if (mShowEventDetailsWithAgenda) {
- View v = getFirstVisibleView ();
- if (v != null) {
- Rect r = new Rect ();
- v.getLocalVisibleRect(r);
- if (r.bottom - r.top <= mWindowAdapter.getStickyHeaderHeight()) {
- position ++;
- }
- }
- }
-
- return mWindowAdapter.getAgendaItemByPosition(position,
- false /* startDay = date separator date instead of actual event startday */);
-
- }
-
- public int getJulianDayFromPosition(int position) {
- DayAdapterInfo info = mWindowAdapter.getAdapterInfoByPosition(position);
- if (info != null) {
- return info.dayAdapter.findJulianDayFromPosition(position - info.offset);
- }
- return 0;
- }
-
- // Finds is a specific event (defined by start time and id) is visible
- public boolean isAgendaItemVisible(Time startTime, long id) {
-
- if (id == -1 || startTime == null) {
- return false;
- }
-
- View child = getChildAt(0);
- // View not set yet, so not child - return
- if (child == null) {
- return false;
- }
- int start = getPositionForView(child);
- long milliTime = startTime.toMillis(true);
- int childCount = getChildCount();
- int eventsInAdapter = mWindowAdapter.getCount();
-
- for (int i = 0; i < childCount; i++) {
- if (i + start >= eventsInAdapter) {
- break;
- }
- AgendaItem agendaItem = mWindowAdapter.getAgendaItemByPosition(i + start);
- if (agendaItem == null) {
- continue;
- }
- if (agendaItem.id == id && agendaItem.begin == milliTime) {
- View listItem = getChildAt(i);
- if (listItem.getTop() <= getHeight() &&
- listItem.getTop() >= mWindowAdapter.getStickyHeaderHeight()) {
- return true;
- }
- }
- }
- return false;
- }
-
- public long getSelectedInstanceId() {
- return mWindowAdapter.getSelectedInstanceId();
- }
-
- public void setSelectedInstanceId(long id) {
- mWindowAdapter.setSelectedInstanceId(id);
- }
-
- // 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() {
- mTZUpdater.run();
- Utils.setMidnightUpdater(mHandler, mMidnightUpdater, mTimeZone);
- setPastEventsUpdater();
- mWindowAdapter.onResume();
- }
-
- public void onPause() {
- Utils.resetMidnightUpdater(mHandler, mMidnightUpdater);
- resetPastEventsUpdater();
- }
-}
diff --git a/src/com/android/calendar/agenda/AgendaWindowAdapter.java b/src/com/android/calendar/agenda/AgendaWindowAdapter.java
deleted file mode 100644
index 9fd59f0f..00000000
--- a/src/com/android/calendar/agenda/AgendaWindowAdapter.java
+++ /dev/null
@@ -1,1412 +0,0 @@
-/*
- * 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.agenda;
-
-import android.app.Activity;
-import android.content.AsyncQueryHandler;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Handler;
-import android.provider.CalendarContract;
-import android.provider.CalendarContract.Attendees;
-import android.provider.CalendarContract.Calendars;
-import android.provider.CalendarContract.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.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.AbsListView.OnScrollListener;
-import android.widget.BaseAdapter;
-import android.widget.GridLayout;
-import android.widget.TextView;
-
-import com.android.calendar.CalendarController;
-import com.android.calendar.CalendarController.EventType;
-import com.android.calendar.CalendarController.ViewType;
-import com.android.calendar.R;
-import com.android.calendar.StickyHeaderListView;
-import com.android.calendar.Utils;
-
-import java.util.Date;
-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
- implements StickyHeaderListView.HeaderIndexer, StickyHeaderListView.HeaderHeightListener{
-
- static final boolean BASICLOG = false;
- static final boolean DEBUGLOG = false;
- private static final String TAG = "AgendaWindowAdapter";
-
- private static final String AGENDA_SORT_ORDER =
- CalendarContract.Instances.START_DAY + " ASC, " +
- CalendarContract.Instances.BEGIN + " ASC, " +
- CalendarContract.Events.TITLE + " ASC";
-
- public static final int INDEX_INSTANCE_ID = 0;
- 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 int INDEX_ORGANIZER = 13;
- public static final int INDEX_OWNER_ACCOUNT = 14;
- public static final int INDEX_CAN_ORGANIZER_RESPOND= 15;
- public static final int INDEX_TIME_ZONE = 16;
-
- 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.DISPLAY_COLOR, // 5 If SDK < 16, set to Instances.CALENDAR_COLOR.
- 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
- Instances.ORGANIZER, // 13
- Instances.OWNER_ACCOUNT, // 14
- Instances.CAN_ORGANIZER_RESPOND, // 15
- Instances.EVENT_TIMEZONE, // 16
- };
-
- static {
- if (!Utils.isJellybeanOrLater()) {
- PROJECTION[INDEX_COLOR] = Instances.CALENDAR_COLOR;
- }
- }
-
- // Listview may have a bug where the index/position is not consistent when there's a header.
- // position == positionInListView - OFF_BY_ONE_BUG
- // 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 = 1;
-
- private final Context mContext;
- private final Resources mResources;
- private final QueryHandler mQueryHandler;
- private final AgendaListView mAgendaListView;
-
- /** The sum of the rows in all the adapters */
- private int mRowCount;
-
- /** The number of times we have queried and gotten no results back */
- private int mEmptyCursorCount;
-
- /** Cached value of the last used adapter */
- private DayAdapterInfo mLastUsedInfo;
-
- private final LinkedList<DayAdapterInfo> mAdapterInfos =
- new LinkedList<DayAdapterInfo>();
- private final ConcurrentLinkedQueue<QuerySpec> mQueryQueue =
- new ConcurrentLinkedQueue<QuerySpec>();
- private final TextView mHeaderView;
- private final TextView mFooterView;
- private boolean mDoneSettingUpHeaderFooter = false;
-
- private final boolean mIsTabletConfig;
-
- boolean mCleanQueryInitiated = false;
- private int mStickyHeaderSize = 44; // Initial size big enough for it to work
-
- /**
- * 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 final Formatter mFormatter;
- private final StringBuilder mStringBuilder;
- private String mTimeZone;
-
- // defines if to pop-up the current event when the agenda is first shown
- private final boolean mShowEventOnStart;
-
- private final Runnable mTZUpdater = new Runnable() {
- @Override
- public void run() {
- mTimeZone = Utils.getTimeZone(mContext, this);
- notifyDataSetChanged();
- }
- };
-
- private final Handler mDataChangedHandler = new Handler();
- private final Runnable mDataChangedRunnable = new Runnable() {
- @Override
- public void run() {
- notifyDataSetChanged();
- }
- };
-
- private boolean mShuttingDown;
- private boolean mHideDeclined;
-
- // Used to stop a fling motion if the ListView is set to a specific position
- int mListViewScrollState = OnScrollListener.SCROLL_STATE_IDLE;
-
- /** The current search query, or null if none */
- private String mSearchQuery;
-
- private long mSelectedInstanceId = -1;
-
- private final int mSelectedItemBackgroundColor;
- private final int mSelectedItemTextColor;
- private final float mItemRightMargin;
-
- // 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;
- String searchQuery;
- int queryType;
- long id;
-
- public QuerySpec(int queryType) {
- this.queryType = queryType;
- id = -1;
- }
-
- @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 (searchQuery != null) {
- result = prime * result + searchQuery.hashCode();
- }
- if (goToTime != null) {
- long goToTimeMillis = goToTime.toMillis(false);
- result = prime * result + (int) (goToTimeMillis ^ (goToTimeMillis >>> 32));
- }
- result = prime * result + (int)id;
- 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
- || Utils.equals(searchQuery, other.searchQuery) || id != other.id) {
- return false;
- }
-
- if (goToTime != null) {
- if (goToTime.toMillis(false) != other.goToTime.toMillis(false)) {
- return false;
- }
- } else {
- if (other.goToTime != null) {
- return false;
- }
- }
- return true;
- }
- }
-
- /**
- * Class representing a list item within the Agenda view. Could be either an instance of an
- * event, or a header marking the specific day.
- *
- * The begin and end times of an AgendaItem should always be in local time, even if the event
- * is all day. buildAgendaItemFromCursor() converts each event to local time.
- */
- static class AgendaItem {
- long begin;
- long end;
- long id;
- int startDay;
- boolean allDay;
- }
-
- 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() {
- // Static class, so the time in this toString will not reflect the
- // home tz settings. This should only affect debugging.
- 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(Context context,
- AgendaListView agendaListView, boolean showEventOnStart) {
- mContext = context;
- mResources = context.getResources();
- mSelectedItemBackgroundColor = mResources
- .getColor(R.color.agenda_selected_background_color);
- mSelectedItemTextColor = mResources.getColor(R.color.agenda_selected_text_color);
- mItemRightMargin = mResources.getDimension(R.dimen.agenda_item_right_margin);
- mIsTabletConfig = Utils.getConfigBool(mContext, R.bool.tablet_config);
-
- mTimeZone = Utils.getTimeZone(context, mTZUpdater);
- mAgendaListView = agendaListView;
- mQueryHandler = new QueryHandler(context.getContentResolver());
-
- mStringBuilder = new StringBuilder(50);
- mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
-
- mShowEventOnStart = showEventOnStart;
-
- // Implies there is no sticky header
- if (!mShowEventOnStart) {
- mStickyHeaderSize = 0;
- }
- mSearchQuery = null;
-
- LayoutInflater inflater = (LayoutInflater) context
- .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
- @Override
- public long getItemId(int position) {
- DayAdapterInfo info = getAdapterInfoByPosition(position);
- if (info != null) {
- int curPos = info.dayAdapter.getCursorPosition(position - info.offset);
- if (curPos == Integer.MIN_VALUE) {
- return -1;
- }
- // Regular event
- if (curPos >= 0) {
- info.cursor.moveToPosition(curPos);
- return info.cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID) << 20 +
- info.cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
- }
- // Day Header
- return info.dayAdapter.findJulianDayFromPosition(position);
-
- } 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));
- }
-
- final View v;
- DayAdapterInfo info = getAdapterInfoByPosition(position);
- if (info != null) {
- int offset = position - info.offset;
- v = info.dayAdapter.getView(offset, convertView,
- parent);
-
- // Turn on the past/present separator if the view is a day header
- // and it is the first day with events after yesterday.
- if (info.dayAdapter.isDayHeaderView(offset)) {
- View simpleDivider = v.findViewById(R.id.top_divider_simple);
- View pastPresentDivider = v.findViewById(R.id.top_divider_past_present);
- if (info.dayAdapter.isFirstDayAfterYesterday(offset)) {
- if (simpleDivider != null && pastPresentDivider != null) {
- simpleDivider.setVisibility(View.GONE);
- pastPresentDivider.setVisibility(View.VISIBLE);
- }
- } else if (simpleDivider != null && pastPresentDivider != null) {
- simpleDivider.setVisibility(View.VISIBLE);
- pastPresentDivider.setVisibility(View.GONE);
- }
- }
- } else {
- // TODO
- Log.e(TAG, "BUG: getAdapterInfoByPosition returned null!!! " + position);
- TextView tv = new TextView(mContext);
- tv.setText("Bug! " + position);
- v = tv;
- }
-
- // If this is not a tablet config don't do selection highlighting
- if (!mIsTabletConfig) {
- return v;
- }
- // Show selected marker if this is item is selected
- boolean selected = false;
- Object yy = v.getTag();
- if (yy instanceof AgendaAdapter.ViewHolder) {
- AgendaAdapter.ViewHolder vh = (AgendaAdapter.ViewHolder) yy;
- selected = mSelectedInstanceId == vh.instanceId;
- vh.selectedMarker.setVisibility((selected && mShowEventOnStart) ?
- View.VISIBLE : View.GONE);
- if (mShowEventOnStart) {
- GridLayout.LayoutParams lp =
- (GridLayout.LayoutParams)vh.textContainer.getLayoutParams();
- if (selected) {
- mSelectedVH = vh;
- v.setBackgroundColor(mSelectedItemBackgroundColor);
- vh.title.setTextColor(mSelectedItemTextColor);
- vh.when.setTextColor(mSelectedItemTextColor);
- vh.where.setTextColor(mSelectedItemTextColor);
- lp.setMargins(0, 0, 0, 0);
- vh.textContainer.setLayoutParams(lp);
- } else {
- lp.setMargins(0, 0, (int)mItemRightMargin, 0);
- vh.textContainer.setLayoutParams(lp);
- }
- }
- }
-
- if (DEBUGLOG) {
- Log.e(TAG, "getView " + position + " = " + getViewTitle(v));
- }
- return v;
- }
-
- private AgendaAdapter.ViewHolder mSelectedVH = null;
-
- private int findEventPositionNearestTime(Time time, long id) {
- DayAdapterInfo info = getAdapterInfoByTime(time);
- int pos = -1;
- if (info != null) {
- pos = info.offset + info.dayAdapter.findEventPositionNearestTime(time, id);
- }
- if (DEBUGLOG) Log.e(TAG, "findEventPositionNearestTime " + time + " id:" + id + " =" + pos);
- return pos;
- }
-
- protected 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 AgendaItem getAgendaItemByPosition(final int positionInListView) {
- return getAgendaItemByPosition(positionInListView, true);
- }
-
- /**
- * Return the event info for a given position in the adapter
- * @param positionInListView
- * @param returnEventStartDay If true, return actual event startday. Otherwise
- * return agenda date-header date as the startDay.
- * The two will differ for multi-day events after the first day.
- * @return
- */
- public AgendaItem getAgendaItemByPosition(final int positionInListView,
- boolean returnEventStartDay) {
- if (DEBUGLOG) Log.e(TAG, "getEventByPosition " + positionInListView);
- if (positionInListView < 0) {
- return null;
- }
-
- final int positionInAdapter = positionInListView - OFF_BY_ONE_BUG;
- DayAdapterInfo info = getAdapterInfoByPosition(positionInAdapter);
- if (info == null) {
- return null;
- }
-
- int cursorPosition = info.dayAdapter.getCursorPosition(positionInAdapter - info.offset);
- if (cursorPosition == Integer.MIN_VALUE) {
- return null;
- }
-
- boolean isDayHeader = false;
- if (cursorPosition < 0) {
- cursorPosition = -cursorPosition;
- isDayHeader = true;
- }
-
- if (cursorPosition < info.cursor.getCount()) {
- AgendaItem item = buildAgendaItemFromCursor(info.cursor, cursorPosition, isDayHeader);
- if (!returnEventStartDay && !isDayHeader) {
- item.startDay = info.dayAdapter.findJulianDayFromPosition(positionInAdapter -
- info.offset);
- }
- return item;
- }
- return null;
- }
-
- private AgendaItem buildAgendaItemFromCursor(final Cursor cursor, int cursorPosition,
- boolean isDayHeader) {
- if (cursorPosition == -1) {
- cursor.moveToFirst();
- } else {
- cursor.moveToPosition(cursorPosition);
- }
- AgendaItem agendaItem = new AgendaItem();
- agendaItem.begin = cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
- agendaItem.end = cursor.getLong(AgendaWindowAdapter.INDEX_END);
- agendaItem.startDay = cursor.getInt(AgendaWindowAdapter.INDEX_START_DAY);
- agendaItem.allDay = cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
- if (agendaItem.allDay) { // UTC to Local time conversion
- Time time = new Time(mTimeZone);
- time.setJulianDay(Time.getJulianDay(agendaItem.begin, 0));
- agendaItem.begin = time.toMillis(false /* use isDst */);
- } else if (isDayHeader) { // Trim to midnight.
- Time time = new Time(mTimeZone);
- time.set(agendaItem.begin);
- time.hour = 0;
- time.minute = 0;
- time.second = 0;
- agendaItem.begin = time.toMillis(false /* use isDst */);
- }
-
- // If this is not a day header, then it's an event.
- if (!isDayHeader) {
- agendaItem.id = cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID);
- if (agendaItem.allDay) {
- Time time = new Time(mTimeZone);
- time.setJulianDay(Time.getJulianDay(agendaItem.end, 0));
- agendaItem.end = time.toMillis(false /* use isDst */);
- }
- }
- return agendaItem;
- }
-
- /**
- * Ensures that any all day events are converted to UTC before a VIEW_EVENT command is sent.
- */
- private void sendViewEvent(AgendaItem item, long selectedTime) {
- long startTime;
- long endTime;
- if (item.allDay) {
- startTime = Utils.convertAlldayLocalToUTC(null, item.begin, mTimeZone);
- endTime = Utils.convertAlldayLocalToUTC(null, item.end, mTimeZone);
- } else {
- startTime = item.begin;
- endTime = item.end;
- }
- if (DEBUGLOG) {
- Log.d(TAG, "Sent (AgendaWindowAdapter): VIEW EVENT: " + new Date(startTime));
- }
- CalendarController.getInstance(mContext)
- .sendEventRelatedEventWithExtra(this, EventType.VIEW_EVENT,
- item.id, startTime, endTime, 0,
- 0, CalendarController.EventInfo.buildViewExtraLong(
- Attendees.ATTENDEE_STATUS_NONE,
- item.allDay), selectedTime);
- }
-
- public void refresh(Time goToTime, long id, String searchQuery, boolean forced,
- boolean refreshEventInfo) {
- if (searchQuery != null) {
- mSearchQuery = searchQuery;
- }
-
- if (DEBUGLOG) {
- Log.e(TAG, this + ": refresh " + goToTime.toString() + " id " + id
- + ((searchQuery != null) ? searchQuery : "")
- + (forced ? " forced" : " not forced")
- + (refreshEventInfo ? " refresh event info" : ""));
- }
-
- int startDay = Time.getJulianDay(goToTime.toMillis(false), goToTime.gmtoff);
-
- if (!forced && isInRange(startDay, startDay)) {
- // No need to re-query
- if (!mAgendaListView.isAgendaItemVisible(goToTime, id)) {
- int gotoPosition = findEventPositionNearestTime(goToTime, id);
- if (gotoPosition > 0) {
- mAgendaListView.setSelectionFromTop(gotoPosition +
- OFF_BY_ONE_BUG, mStickyHeaderSize);
- if (mListViewScrollState == OnScrollListener.SCROLL_STATE_FLING) {
- mAgendaListView.smoothScrollBy(0, 0);
- }
- if (refreshEventInfo) {
- long newInstanceId = findInstanceIdFromPosition(gotoPosition);
- if (newInstanceId != getSelectedInstanceId()) {
- setSelectedInstanceId(newInstanceId);
- mDataChangedHandler.post(mDataChangedRunnable);
- Cursor tempCursor = getCursorByPosition(gotoPosition);
- if (tempCursor != null) {
- int tempCursorPosition = getCursorPositionByPosition(gotoPosition);
- AgendaItem item =
- buildAgendaItemFromCursor(tempCursor, tempCursorPosition,
- false);
- mSelectedVH = new AgendaAdapter.ViewHolder();
- mSelectedVH.allDay = item.allDay;
- sendViewEvent(item, goToTime.toMillis(false));
- }
- }
- }
- }
-
- Time actualTime = new Time(mTimeZone);
- actualTime.set(goToTime);
- CalendarController.getInstance(mContext).sendEvent(this, EventType.UPDATE_TITLE,
- actualTime, actualTime, -1, ViewType.CURRENT);
- }
- return;
- }
-
- // If AllInOneActivity is sending a second GOTO event(in OnResume), ignore it.
- if (!mCleanQueryInitiated || searchQuery != null) {
- // Query for a total of MIN_QUERY_DURATION days
- int endDay = startDay + MIN_QUERY_DURATION;
-
- mSelectedInstanceId = -1;
- mCleanQueryInitiated = true;
- queueQuery(startDay, endDay, goToTime, searchQuery, QUERY_TYPE_CLEAN, id);
-
- // Pre-fetch more data to overcome a race condition in AgendaListView.shiftSelection
- // Queuing more data with the goToTime set to the selected time skips the call to
- // shiftSelection on refresh.
- mOlderRequests++;
- queueQuery(0, 0, goToTime, searchQuery, QUERY_TYPE_OLDER, id);
- mNewerRequests++;
- queueQuery(0, 0, goToTime, searchQuery, QUERY_TYPE_NEWER, id);
- }
- }
-
- 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) {
- // TODO the following causes ANR's. Do this in a thread.
- 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.VISIBLE + "=1 AND "
- + Instances.SELF_ATTENDEE_STATUS + "!="
- + Attendees.ATTENDEE_STATUS_DECLINED;
- } else {
- return Calendars.VISIBLE + "=1";
- }
- }
-
- private Uri buildQueryUri(int start, int end, String searchQuery) {
- Uri rootUri = searchQuery == null ?
- Instances.CONTENT_BY_DAY_URI :
- Instances.CONTENT_SEARCH_BY_DAY_URI;
- Uri.Builder builder = rootUri.buildUpon();
- ContentUris.appendId(builder, start);
- ContentUris.appendId(builder, end);
- if (searchQuery != null) {
- builder.appendPath(searchQuery);
- }
- return builder.build();
- }
-
- 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,
- String searchQuery, int queryType, long id) {
- QuerySpec queryData = new QuerySpec(queryType);
- queryData.goToTime = new Time(goToTime); // Creates a new time reference per QuerySpec.
- queryData.start = start;
- queryData.end = end;
- queryData.searchQuery = searchQuery;
- queryData.id = id;
- return queueQuery(queryData);
- }
-
- private boolean queueQuery(QuerySpec queryData) {
- queryData.searchQuery = mSearchQuery;
- 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;
- }
-
- // By "compacting" cursors, this fixes the disco/ping-pong problem
- // b/5311977
- if (mRowCount < 20 && queryData.queryType != QUERY_TYPE_CLEAN) {
- if (DEBUGLOG) {
- Log.e(TAG, "Compacting cursor: mRowCount=" + mRowCount
- + " totalStart:" + start
- + " totalEnd:" + end
- + " query.start:" + queryData.start
- + " query.end:" + queryData.end);
- }
-
- queryData.queryType = QUERY_TYPE_CLEAN;
-
- if (queryData.start > start) {
- queryData.start = start;
- }
- if (queryData.end < end) {
- queryData.end = end;
- }
- }
- }
-
- if (BASICLOG) {
- Time time = new Time(mTimeZone);
- time.setJulianDay(queryData.start);
- Time time2 = new Time(mTimeZone);
- 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();
-
- Uri queryUri = buildQueryUri(
- queryData.start, queryData.end, queryData.searchQuery);
- mQueryHandler.startQuery(0, queryData, queryUri,
- PROJECTION, buildQuerySelection(), null,
- AGENDA_SORT_ORDER);
- }
-
- private String formatDateString(int julianDay) {
- Time time = new Time(mTimeZone);
- 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, mTimeZone).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) {
- if (DEBUGLOG) {
- Log.d(TAG, "(+)onQueryComplete");
- }
- QuerySpec data = (QuerySpec)cookie;
-
- if (cursor == null) {
- if (mAgendaListView != null && mAgendaListView.getContext() instanceof Activity) {
- ((Activity) mAgendaListView.getContext()).finish();
- }
- return;
- }
-
- if (BASICLOG) {
- long queryEndMillis = System.nanoTime();
- Log.e(TAG, "Query time(ms): "
- + (queryEndMillis - data.queryStartMillis) / 1000000
- + " Count: " + cursor.getCount());
- }
-
- if (data.queryType == QUERY_TYPE_CLEAN) {
- mCleanQueryInitiated = false;
- }
-
- if (mShuttingDown) {
- cursor.close();
- return;
- }
-
- // Notify Listview of changes and update position
- int cursorSize = cursor.getCount();
- if (cursorSize > 0 || mAdapterInfos.isEmpty() || data.queryType == QUERY_TYPE_CLEAN) {
- final int listPositionOffset = processNewCursor(data, cursor);
- int newPosition = -1;
- 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();
- newPosition = findEventPositionNearestTime(goToTime, data.id);
- if (newPosition >= 0) {
- if (mListViewScrollState == OnScrollListener.SCROLL_STATE_FLING) {
- mAgendaListView.smoothScrollBy(0, 0);
- }
- mAgendaListView.setSelectionFromTop(newPosition + OFF_BY_ONE_BUG,
- mStickyHeaderSize);
- Time actualTime = new Time(mTimeZone);
- actualTime.set(goToTime);
- if (DEBUGLOG) {
- Log.d(TAG, "onQueryComplete: Updating title...");
- }
- CalendarController.getInstance(mContext).sendEvent(this,
- EventType.UPDATE_TITLE, actualTime, actualTime, -1,
- ViewType.CURRENT);
- }
- if (DEBUGLOG) {
- Log.e(TAG, "Setting listview to " +
- "findEventPositionNearestTime: " + (newPosition + OFF_BY_ONE_BUG));
- }
- }
-
- // Make sure we change the selected instance Id only on a clean query and we
- // do not have one set already
- if (mSelectedInstanceId == -1 && newPosition != -1 &&
- data.queryType == QUERY_TYPE_CLEAN) {
- if (data.id != -1 || data.goToTime != null) {
- mSelectedInstanceId = findInstanceIdFromPosition(newPosition);
- }
- }
-
- // size == 1 means a fresh query. Possibly after the data changed.
- // Let's check whether mSelectedInstanceId is still valid.
- if (mAdapterInfos.size() == 1 && mSelectedInstanceId != -1) {
- boolean found = false;
- cursor.moveToPosition(-1);
- while (cursor.moveToNext()) {
- if (mSelectedInstanceId == cursor
- .getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID)) {
- found = true;
- break;
- }
- };
-
- if (!found) {
- mSelectedInstanceId = -1;
- }
- }
-
- // Show the requested event
- if (mShowEventOnStart && data.queryType == QUERY_TYPE_CLEAN) {
- Cursor tempCursor = null;
- int tempCursorPosition = -1;
-
- // If no valid event is selected , just pick the first one
- if (mSelectedInstanceId == -1) {
- if (cursor.moveToFirst()) {
- mSelectedInstanceId = cursor
- .getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID);
- // Set up a dummy view holder so we have the right all day
- // info when the view is created.
- // TODO determine the full set of what might be useful to
- // know about the selected view and fill it in.
- mSelectedVH = new AgendaAdapter.ViewHolder();
- mSelectedVH.allDay =
- cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
- tempCursor = cursor;
- }
- } else if (newPosition != -1) {
- tempCursor = getCursorByPosition(newPosition);
- tempCursorPosition = getCursorPositionByPosition(newPosition);
- }
- if (tempCursor != null) {
- AgendaItem item = buildAgendaItemFromCursor(tempCursor, tempCursorPosition,
- false);
- long selectedTime = findStartTimeFromPosition(newPosition);
- if (DEBUGLOG) {
- Log.d(TAG, "onQueryComplete: Sending View Event...");
- }
- sendViewEvent(item, selectedTime);
- }
- }
- } 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);
-
- // Go over the events and mark the first day after yesterday
- // that has events in it
- // If the range of adapters doesn't include yesterday, skip marking it since it will
- // mark the first day in the adapters.
- synchronized (mAdapterInfos) {
- DayAdapterInfo info = mAdapterInfos.getFirst();
- Time time = new Time(mTimeZone);
- long now = System.currentTimeMillis();
- time.set(now);
- int JulianToday = Time.getJulianDay(now, time.gmtoff);
- if (info != null && JulianToday >= info.start && JulianToday
- <= mAdapterInfos.getLast().end) {
- Iterator<DayAdapterInfo> iter = mAdapterInfos.iterator();
- boolean foundDay = false;
- while (iter.hasNext() && !foundDay) {
- info = iter.next();
- for (int i = 0; i < info.size; i++) {
- if (info.dayAdapter.findJulianDayFromPosition(i) >= JulianToday) {
- info.dayAdapter.setAsFirstDayAfterYesterday(i);
- foundDay = true;
- break;
- }
- }
- }
- }
- }
-
- // Fire off the next query if any
- Iterator<QuerySpec> it = mQueryQueue.iterator();
- while (it.hasNext()) {
- QuerySpec queryData = it.next();
- if (queryData.queryType == QUERY_TYPE_CLEAN
- || !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 onResume() {
- mTZUpdater.run();
- }
-
- public void setHideDeclinedEvents(boolean hideDeclined) {
- mHideDeclined = hideDeclined;
- }
-
- public void setSelectedView(View v) {
- if (v != null) {
- Object vh = v.getTag();
- if (vh instanceof AgendaAdapter.ViewHolder) {
- mSelectedVH = (AgendaAdapter.ViewHolder) vh;
- if (mSelectedInstanceId != mSelectedVH.instanceId) {
- mSelectedInstanceId = mSelectedVH.instanceId;
- notifyDataSetChanged();
- }
- }
- }
- }
-
- public AgendaAdapter.ViewHolder getSelectedViewHolder() {
- return mSelectedVH;
- }
-
- public long getSelectedInstanceId() {
- return mSelectedInstanceId;
- }
-
- public void setSelectedInstanceId(long selectedInstanceId) {
- mSelectedInstanceId = selectedInstanceId;
- mSelectedVH = null;
- }
-
- private long findInstanceIdFromPosition(int position) {
- DayAdapterInfo info = getAdapterInfoByPosition(position);
- if (info != null) {
- return info.dayAdapter.getInstanceId(position - info.offset);
- }
- return -1;
- }
-
- private long findStartTimeFromPosition(int position) {
- DayAdapterInfo info = getAdapterInfoByPosition(position);
- if (info != null) {
- return info.dayAdapter.getStartTime(position - info.offset);
- }
- return -1;
- }
-
-
- private Cursor getCursorByPosition(int position) {
- DayAdapterInfo info = getAdapterInfoByPosition(position);
- if (info != null) {
- return info.cursor;
- }
- return null;
- }
-
- private int getCursorPositionByPosition(int position) {
- DayAdapterInfo info = getAdapterInfoByPosition(position);
- if (info != null) {
- return info.dayAdapter.getCursorPosition(position - info.offset);
- }
- return -1;
- }
-
- // Implementation of HeaderIndexer interface for StickyHeeaderListView
-
- // Returns the location of the day header of a specific event specified in the position
- // in the adapter
- @Override
- public int getHeaderPositionFromItemPosition(int position) {
-
- // For phone configuration, return -1 so there will be no sticky header
- if (!mIsTabletConfig) {
- return -1;
- }
-
- DayAdapterInfo info = getAdapterInfoByPosition(position);
- if (info != null) {
- int pos = info.dayAdapter.getHeaderPosition(position - info.offset);
- return (pos != -1)?(pos + info.offset):-1;
- }
- return -1;
- }
-
- // Returns the number of events for a specific day header
- @Override
- public int getHeaderItemsNumber(int headerPosition) {
- if (headerPosition < 0 || !mIsTabletConfig) {
- return -1;
- }
- DayAdapterInfo info = getAdapterInfoByPosition(headerPosition);
- if (info != null) {
- return info.dayAdapter.getHeaderItemsCount(headerPosition - info.offset);
- }
- return -1;
- }
-
- @Override
- public void OnHeaderHeightChanged(int height) {
- mStickyHeaderSize = height;
- }
-
- public int getStickyHeaderHeight() {
- return mStickyHeaderSize;
- }
-
- public void setScrollState(int state) {
- mListViewScrollState = state;
- }
-}
diff --git a/src/com/android/calendar/alerts/AlertActivity.java b/src/com/android/calendar/alerts/AlertActivity.java
deleted file mode 100644
index 78733bd4..00000000
--- a/src/com/android/calendar/alerts/AlertActivity.java
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * 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.alerts;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.app.NotificationManager;
-import android.app.TaskStackBuilder;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.provider.CalendarContract;
-import android.provider.CalendarContract.CalendarAlerts;
-import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.Button;
-import android.widget.ListView;
-
-import com.android.calendar.AsyncQueryService;
-import com.android.calendar.EventInfoActivity;
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-import com.android.calendar.alerts.GlobalDismissManager.AlarmId;
-
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * The alert panel that pops up when there is a calendar event alarm.
- * This activity is started by an intent that specifies an event id.
- */
-public class AlertActivity extends Activity implements OnClickListener {
- private static final String TAG = "AlertActivity";
-
- private static final String[] PROJECTION = new String[] {
- CalendarAlerts._ID, // 0
- CalendarAlerts.TITLE, // 1
- CalendarAlerts.EVENT_LOCATION, // 2
- CalendarAlerts.ALL_DAY, // 3
- CalendarAlerts.BEGIN, // 4
- CalendarAlerts.END, // 5
- CalendarAlerts.EVENT_ID, // 6
- CalendarAlerts.CALENDAR_COLOR, // 7
- CalendarAlerts.RRULE, // 8
- CalendarAlerts.HAS_ALARM, // 9
- CalendarAlerts.STATE, // 10
- CalendarAlerts.ALARM_TIME, // 11
- };
-
- public static final int INDEX_ROW_ID = 0;
- 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_BEGIN = 4;
- public static final int INDEX_END = 5;
- public static final int INDEX_EVENT_ID = 6;
- public static final int INDEX_COLOR = 7;
- public static final int INDEX_RRULE = 8;
- public static final int INDEX_HAS_ALARM = 9;
- public static final int INDEX_STATE = 10;
- public static final int INDEX_ALARM_TIME = 11;
-
- private static final String SELECTION = CalendarAlerts.STATE + "=?";
- private static final String[] SELECTIONARG = new String[] {
- Integer.toString(CalendarAlerts.STATE_FIRED)
- };
-
- private AlertAdapter mAdapter;
- private QueryHandler mQueryHandler;
- private Cursor mCursor;
- private ListView mListView;
- private Button mDismissAllButton;
-
-
- private void dismissFiredAlarms() {
- ContentValues values = new ContentValues(1 /* size */);
- values.put(PROJECTION[INDEX_STATE], CalendarAlerts.STATE_DISMISSED);
- String selection = CalendarAlerts.STATE + "=" + CalendarAlerts.STATE_FIRED;
- mQueryHandler.startUpdate(0, null, CalendarAlerts.CONTENT_URI, values,
- selection, null /* selectionArgs */, Utils.UNDO_DELAY);
-
- if (mCursor == null) {
- Log.e(TAG, "Unable to globally dismiss all notifications because cursor was null.");
- return;
- }
- if (mCursor.isClosed()) {
- Log.e(TAG, "Unable to globally dismiss all notifications because cursor was closed.");
- return;
- }
- if (!mCursor.moveToFirst()) {
- Log.e(TAG, "Unable to globally dismiss all notifications because cursor was empty.");
- return;
- }
-
- List<AlarmId> alarmIds = new LinkedList<AlarmId>();
- do {
- long eventId = mCursor.getLong(INDEX_EVENT_ID);
- long eventStart = mCursor.getLong(INDEX_BEGIN);
- alarmIds.add(new AlarmId(eventId, eventStart));
- } while (mCursor.moveToNext());
- initiateGlobalDismiss(alarmIds);
- }
-
- private void dismissAlarm(long id, long eventId, long startTime) {
- ContentValues values = new ContentValues(1 /* size */);
- values.put(PROJECTION[INDEX_STATE], CalendarAlerts.STATE_DISMISSED);
- String selection = CalendarAlerts._ID + "=" + id;
- mQueryHandler.startUpdate(0, null, CalendarAlerts.CONTENT_URI, values,
- selection, null /* selectionArgs */, Utils.UNDO_DELAY);
-
- List<AlarmId> alarmIds = new LinkedList<AlarmId>();
- alarmIds.add(new AlarmId(eventId, startTime));
- initiateGlobalDismiss(alarmIds);
- }
-
- @SuppressWarnings("unchecked")
- private void initiateGlobalDismiss(List<AlarmId> alarmIds) {
- new AsyncTask<List<AlarmId>, Void, Void>() {
- @Override
- protected Void doInBackground(List<AlarmId>... params) {
- GlobalDismissManager.dismissGlobally(getApplicationContext(), params[0]);
- return null;
- }
- }.execute(alarmIds);
- }
-
- private class QueryHandler extends AsyncQueryService {
- public QueryHandler(Context context) {
- super(context);
- }
-
- @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()) {
- mCursor = cursor;
- mAdapter.changeCursor(cursor);
- mListView.setSelection(cursor.getCount() - 1);
-
- // The results are in, enable the buttons
- mDismissAllButton.setEnabled(true);
- } else {
- cursor.close();
- }
- }
-
- @Override
- protected void onUpdateComplete(int token, Object cookie, int result) {
- // Ignore
- }
- }
-
- private final OnItemClickListener mViewListener = new OnItemClickListener() {
-
- @SuppressLint("NewApi")
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position,
- long i) {
- AlertActivity alertActivity = AlertActivity.this;
- Cursor cursor = alertActivity.getItemForView(view);
-
- long alarmId = cursor.getLong(INDEX_ROW_ID);
- long eventId = cursor.getLong(AlertActivity.INDEX_EVENT_ID);
- long startMillis = cursor.getLong(AlertActivity.INDEX_BEGIN);
-
- // Mark this alarm as DISMISSED
- dismissAlarm(alarmId, eventId, startMillis);
-
- // build an intent and task stack to start EventInfoActivity with AllInOneActivity
- // as the parent activity rooted to home.
- long endMillis = cursor.getLong(AlertActivity.INDEX_END);
- Intent eventIntent = AlertUtils.buildEventViewIntent(AlertActivity.this, eventId,
- startMillis, endMillis);
-
- if (Utils.isJellybeanOrLater()) {
- TaskStackBuilder.create(AlertActivity.this).addParentStack(EventInfoActivity.class)
- .addNextIntent(eventIntent).startActivities();
- } else {
- alertActivity.startActivity(eventIntent);
- }
-
- alertActivity.finish();
- }
- };
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- setContentView(R.layout.alert_activity);
- setTitle(R.string.alert_title);
-
- mQueryHandler = new QueryHandler(this);
- mAdapter = new AlertAdapter(this, R.layout.alert_item);
-
- mListView = (ListView) findViewById(R.id.alert_container);
- mListView.setItemsCanFocus(true);
- mListView.setAdapter(mAdapter);
- mListView.setOnItemClickListener(mViewListener);
-
- mDismissAllButton = (Button) findViewById(R.id.dismiss_all);
- mDismissAllButton.setOnClickListener(this);
-
- // Disable the buttons, since they need mCursor, which is created asynchronously
- mDismissAllButton.setEnabled(false);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- // If the cursor is null, start the async handler. If it is not null just requery.
- if (mCursor == null) {
- Uri uri = CalendarAlerts.CONTENT_URI_BY_INSTANCE;
- mQueryHandler.startQuery(0, null, uri, PROJECTION, SELECTION, SELECTIONARG,
- CalendarContract.CalendarAlerts.DEFAULT_SORT_ORDER);
- } else {
- if (!mCursor.requery()) {
- Log.w(TAG, "Cursor#requery() failed.");
- mCursor.close();
- mCursor = null;
- }
- }
- }
-
- void closeActivityIfEmpty() {
- if (mCursor != null && !mCursor.isClosed() && mCursor.getCount() == 0) {
- AlertActivity.this.finish();
- }
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- // Can't run updateAlertNotification in main thread
- AsyncTask task = new AsyncTask<Context, Void, Void>() {
- @Override
- protected Void doInBackground(Context ... params) {
- AlertService.updateAlertNotification(params[0]);
- return null;
- }
- }.execute(this);
-
-
- if (mCursor != null) {
- mCursor.deactivate();
- }
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- if (mCursor != null) {
- mCursor.close();
- }
- }
-
- @Override
- public void onClick(View v) {
- if (v == mDismissAllButton) {
- NotificationManager nm =
- (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- nm.cancelAll();
-
- dismissFiredAlarms();
-
- finish();
- }
- }
-
- public boolean isEmpty() {
- return mCursor != null ? (mCursor.getCount() == 0) : true;
- }
-
- public Cursor getItemForView(View view) {
- final int index = mListView.getPositionForView(view);
- if (index < 0) {
- return null;
- }
- return (Cursor) mListView.getAdapter().getItem(index);
- }
-}
diff --git a/src/com/android/calendar/alerts/AlertAdapter.java b/src/com/android/calendar/alerts/AlertAdapter.java
deleted file mode 100644
index 49e3aa0a..00000000
--- a/src/com/android/calendar/alerts/AlertAdapter.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2008 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.alerts;
-
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.text.TextUtils;
-import android.text.format.DateFormat;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-import android.view.View;
-import android.widget.ResourceCursorAdapter;
-import android.widget.TextView;
-
-import java.util.Locale;
-import java.util.TimeZone;
-
-public class AlertAdapter extends ResourceCursorAdapter {
-
- private static AlertActivity alertActivity;
- private static boolean mFirstTime = true;
- private static int mTitleColor;
- private static int mOtherColor; // non-title fields
- private static int mPastEventColor;
-
- public AlertAdapter(AlertActivity activity, int resource) {
- super(activity, resource, null);
- alertActivity = activity;
- }
-
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- View square = view.findViewById(R.id.color_square);
- int color = Utils.getDisplayColorFromColor(cursor.getInt(AlertActivity.INDEX_COLOR));
- square.setBackgroundColor(color);
-
- // Repeating info
- View repeatContainer = view.findViewById(R.id.repeat_icon);
- String rrule = cursor.getString(AlertActivity.INDEX_RRULE);
- if (!TextUtils.isEmpty(rrule)) {
- repeatContainer.setVisibility(View.VISIBLE);
- } else {
- repeatContainer.setVisibility(View.GONE);
- }
-
- /*
- // Reminder
- boolean hasAlarm = cursor.getInt(AlertActivity.INDEX_HAS_ALARM) != 0;
- if (hasAlarm) {
- AgendaAdapter.updateReminder(view, context, cursor.getLong(AlertActivity.INDEX_BEGIN),
- cursor.getLong(AlertActivity.INDEX_EVENT_ID));
- }
- */
-
- String eventName = cursor.getString(AlertActivity.INDEX_TITLE);
- String location = cursor.getString(AlertActivity.INDEX_EVENT_LOCATION);
- long startMillis = cursor.getLong(AlertActivity.INDEX_BEGIN);
- long endMillis = cursor.getLong(AlertActivity.INDEX_END);
- boolean allDay = cursor.getInt(AlertActivity.INDEX_ALL_DAY) != 0;
-
- updateView(context, view, eventName, location, startMillis, endMillis, allDay);
- }
-
- public static void updateView(Context context, View view, String eventName, String location,
- long startMillis, long endMillis, boolean allDay) {
- Resources res = context.getResources();
-
- TextView titleView = (TextView) view.findViewById(R.id.event_title);
- TextView whenView = (TextView) view.findViewById(R.id.when);
- TextView whereView = (TextView) view.findViewById(R.id.where);
- if (mFirstTime) {
- mPastEventColor = res.getColor(R.color.alert_past_event);
- mTitleColor = res.getColor(R.color.alert_event_title);
- mOtherColor = res.getColor(R.color.alert_event_other);
- mFirstTime = false;
- }
-
- if (endMillis < System.currentTimeMillis()) {
- titleView.setTextColor(mPastEventColor);
- whenView.setTextColor(mPastEventColor);
- whereView.setTextColor(mPastEventColor);
- } else {
- titleView.setTextColor(mTitleColor);
- whenView.setTextColor(mOtherColor);
- whereView.setTextColor(mOtherColor);
- }
-
- // What
- if (eventName == null || eventName.length() == 0) {
- eventName = res.getString(R.string.no_title_label);
- }
- titleView.setText(eventName);
-
- // When
- String when;
- int flags;
- String tz = Utils.getTimeZone(context, null);
- if (allDay) {
- flags = DateUtils.FORMAT_UTC | DateUtils.FORMAT_SHOW_WEEKDAY |
- DateUtils.FORMAT_SHOW_DATE;
- tz = Time.TIMEZONE_UTC;
- } else {
- flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE;
- }
- if (DateFormat.is24HourFormat(context)) {
- flags |= DateUtils.FORMAT_24HOUR;
- }
-
- Time time = new Time(tz);
- time.set(startMillis);
- boolean isDST = time.isDst != 0;
- StringBuilder sb = new StringBuilder(
- Utils.formatDateRange(context, startMillis, endMillis, flags));
- if (!allDay && tz != Time.getCurrentTimezone()) {
- sb.append(" ").append(TimeZone.getTimeZone(tz).getDisplayName(
- isDST, TimeZone.SHORT, Locale.getDefault()));
- }
-
- when = sb.toString();
- whenView.setText(when);
-
- // Where
- if (location == null || location.length() == 0) {
- whereView.setVisibility(View.GONE);
- } else {
- whereView.setText(location);
- whereView.setVisibility(View.VISIBLE);
- }
- }
-
- @Override
- protected void onContentChanged () {
- super.onContentChanged();
-
- // Prevent empty popup notification.
- alertActivity.closeActivityIfEmpty();
- }
-}
diff --git a/src/com/android/calendar/alerts/AlertReceiver.java b/src/com/android/calendar/alerts/AlertReceiver.java
index 83dcc9fc..ce80cae1 100644
--- a/src/com/android/calendar/alerts/AlertReceiver.java
+++ b/src/com/android/calendar/alerts/AlertReceiver.java
@@ -68,192 +68,19 @@ import java.util.regex.Pattern;
public class AlertReceiver extends BroadcastReceiver {
private static final String TAG = "AlertReceiver";
- private static final String MAP_ACTION = "com.android.calendar.MAP";
- private static final String CALL_ACTION = "com.android.calendar.CALL";
- private static final String MAIL_ACTION = "com.android.calendar.MAIL";
- private static final String EXTRA_EVENT_ID = "eventid";
-
// The broadcast for notification refreshes scheduled by the app. This is to
// distinguish the EVENT_REMINDER broadcast sent by the provider.
public static final String EVENT_REMINDER_APP_ACTION =
"com.android.calendar.EVENT_REMINDER_APP";
- static final Object mStartingServiceSync = new Object();
- static PowerManager.WakeLock mStartingService;
- private static final Pattern mBlankLinePattern = Pattern.compile("^\\s*$[\n\r]",
- Pattern.MULTILINE);
-
public static final String ACTION_DISMISS_OLD_REMINDERS = "removeOldReminders";
- private static final int NOTIFICATION_DIGEST_MAX_LENGTH = 3;
-
- private static final String GEO_PREFIX = "geo:";
- private static final String TEL_PREFIX = "tel:";
- private static final int MAX_NOTIF_ACTIONS = 3;
-
- private static Handler sAsyncHandler;
- static {
- HandlerThread thr = new HandlerThread("AlertReceiver async");
- thr.start();
- sAsyncHandler = new Handler(thr.getLooper());
- }
@Override
public void onReceive(final Context context, final Intent intent) {
if (AlertService.DEBUG) {
Log.d(TAG, "onReceive: a=" + intent.getAction() + " " + intent.toString());
}
- if (MAP_ACTION.equals(intent.getAction())) {
- // Try starting the map action.
- // If no map location is found (something changed since the notification was originally
- // fired), update the notifications to express this change.
- final long eventId = intent.getLongExtra(EXTRA_EVENT_ID, -1);
- if (eventId != -1) {
- URLSpan[] urlSpans = getURLSpans(context, eventId);
- Intent geoIntent = createMapActivityIntent(context, urlSpans);
- if (geoIntent != null) {
- // Location was successfully found, so dismiss the shade and start maps.
- context.startActivity(geoIntent);
- closeNotificationShade(context);
- } else {
- // No location was found, so update all notifications.
- // Our alert service does not currently allow us to specify only one
- // specific notification to refresh.
- AlertService.updateAlertNotification(context);
- }
- }
- } else if (CALL_ACTION.equals(intent.getAction())) {
- // Try starting the call action.
- // If no call location is found (something changed since the notification was originally
- // fired), update the notifications to express this change.
- final long eventId = intent.getLongExtra(EXTRA_EVENT_ID, -1);
- if (eventId != -1) {
- URLSpan[] urlSpans = getURLSpans(context, eventId);
- Intent callIntent = createCallActivityIntent(context, urlSpans);
- if (callIntent != null) {
- // Call location was successfully found, so dismiss the shade and start dialer.
- context.startActivity(callIntent);
- closeNotificationShade(context);
- } else {
- // No call location was found, so update all notifications.
- // Our alert service does not currently allow us to specify only one
- // specific notification to refresh.
- AlertService.updateAlertNotification(context);
- }
- }
- } else if (MAIL_ACTION.equals(intent.getAction())) {
- closeNotificationShade(context);
-
- // Now start the email intent.
- final long eventId = intent.getLongExtra(EXTRA_EVENT_ID, -1);
- if (eventId != -1) {
- Intent i = new Intent(context, QuickResponseActivity.class);
- i.putExtra(QuickResponseActivity.EXTRA_EVENT_ID, eventId);
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(i);
- }
- } else {
- Intent i = new Intent();
- i.setClass(context, AlertService.class);
- i.putExtras(intent);
- i.putExtra("action", intent.getAction());
- Uri uri = intent.getData();
-
- // This intent might be a BOOT_COMPLETED so it might not have a Uri.
- if (uri != null) {
- i.putExtra("uri", uri.toString());
- }
- beginStartingService(context, i);
- }
- }
-
- /**
- * Start the service to process the current event notifications, acquiring
- * the wake lock before returning to ensure that the service will run.
- */
- public static void beginStartingService(Context context, Intent intent) {
- synchronized (mStartingServiceSync) {
- if (mStartingService == null) {
- PowerManager pm =
- (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mStartingService = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- "StartingAlertService");
- mStartingService.setReferenceCounted(false);
- }
- mStartingService.acquire();
- context.startService(intent);
- }
- }
-
- /**
- * Called back by the service when it has finished processing notifications,
- * releasing the wake lock if the service is now stopping.
- */
- public static void finishStartingService(Service service, int startId) {
- synchronized (mStartingServiceSync) {
- if (mStartingService != null) {
- if (service.stopSelfResult(startId)) {
- mStartingService.release();
- }
- }
- }
- }
-
- private static PendingIntent createClickEventIntent(Context context, long eventId,
- long startMillis, long endMillis, int notificationId) {
- return createDismissAlarmsIntent(context, eventId, startMillis, endMillis, notificationId,
- DismissAlarmsService.SHOW_ACTION);
- }
-
- private static PendingIntent createDeleteEventIntent(Context context, long eventId,
- long startMillis, long endMillis, int notificationId) {
- return createDismissAlarmsIntent(context, eventId, startMillis, endMillis, notificationId,
- DismissAlarmsService.DISMISS_ACTION);
- }
-
- private static PendingIntent createDismissAlarmsIntent(Context context, long eventId,
- long startMillis, long endMillis, int notificationId, String action) {
- Intent intent = new Intent();
- intent.setClass(context, DismissAlarmsService.class);
- intent.setAction(action);
- intent.putExtra(AlertUtils.EVENT_ID_KEY, eventId);
- intent.putExtra(AlertUtils.EVENT_START_KEY, startMillis);
- intent.putExtra(AlertUtils.EVENT_END_KEY, endMillis);
- intent.putExtra(AlertUtils.NOTIFICATION_ID_KEY, notificationId);
-
- // Must set a field that affects Intent.filterEquals so that the resulting
- // PendingIntent will be a unique instance (the 'extras' don't achieve this).
- // This must be unique for the click event across all reminders (so using
- // event ID + startTime should be unique). This also must be unique from
- // the delete event (which also uses DismissAlarmsService).
- Uri.Builder builder = Events.CONTENT_URI.buildUpon();
- ContentUris.appendId(builder, eventId);
- ContentUris.appendId(builder, startMillis);
- intent.setData(builder.build());
- return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
- }
-
- private static PendingIntent createSnoozeIntent(Context context, long eventId,
- long startMillis, long endMillis, int notificationId) {
- Intent intent = new Intent();
- intent.setClass(context, SnoozeAlarmsService.class);
- intent.putExtra(AlertUtils.EVENT_ID_KEY, eventId);
- intent.putExtra(AlertUtils.EVENT_START_KEY, startMillis);
- intent.putExtra(AlertUtils.EVENT_END_KEY, endMillis);
- intent.putExtra(AlertUtils.NOTIFICATION_ID_KEY, notificationId);
-
- Uri.Builder builder = Events.CONTENT_URI.buildUpon();
- ContentUris.appendId(builder, eventId);
- ContentUris.appendId(builder, startMillis);
- intent.setData(builder.build());
- return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
- }
-
- private static PendingIntent createAlertActivityIntent(Context context) {
- Intent clickIntent = new Intent();
- clickIntent.setClass(context, AlertActivity.class);
- clickIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- return PendingIntent.getActivity(context, 0, clickIntent,
- PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
+ closeNotificationShade(context);
}
public static NotificationWrapper makeBasicNotification(Context context, String title,
@@ -274,45 +101,10 @@ public class AlertReceiver extends BroadcastReceiver {
title = resources.getString(R.string.no_title_label);
}
- // Create an intent triggered by clicking on the status icon, that dismisses the
- // notification and shows the event.
- PendingIntent clickIntent = createClickEventIntent(context, eventId, startMillis,
- endMillis, notificationId);
-
- // Create a delete intent triggered by dismissing the notification.
- PendingIntent deleteIntent = createDeleteEventIntent(context, eventId, startMillis,
- endMillis, notificationId);
-
// Create the base notification.
notificationBuilder.setContentTitle(title);
notificationBuilder.setContentText(summaryText);
notificationBuilder.setSmallIcon(R.drawable.stat_notify_calendar);
- notificationBuilder.setContentIntent(clickIntent);
- notificationBuilder.setDeleteIntent(deleteIntent);
- if (doPopup) {
- notificationBuilder.setFullScreenIntent(createAlertActivityIntent(context), true);
- }
-
- PendingIntent mapIntent = null, callIntent = null, snoozeIntent = null, emailIntent = null;
- if (addActionButtons) {
- // Send map, call, and email intent back to ourself first for a couple reasons:
- // 1) Workaround issue where clicking action button in notification does
- // not automatically close the notification shade.
- // 2) Event information will always be up to date.
-
- // Create map and/or call intents.
- URLSpan[] urlSpans = getURLSpans(context, eventId);
- mapIntent = createMapBroadcastIntent(context, urlSpans, eventId);
- callIntent = createCallBroadcastIntent(context, urlSpans, eventId);
-
- // Create email intent for emailing attendees.
- emailIntent = createBroadcastMailIntent(context, eventId, title);
-
- // Create snooze intent. TODO: change snooze to 10 minutes.
- snoozeIntent = createSnoozeIntent(context, eventId, startMillis, endMillis,
- notificationId);
- }
-
if (Utils.isJellybeanOrLater()) {
// Turn off timestamp.
notificationBuilder.setWhen(0);
@@ -320,554 +112,12 @@ public class AlertReceiver extends BroadcastReceiver {
// Should be one of the values in Notification (ie. Notification.PRIORITY_HIGH, etc).
// A higher priority will encourage notification manager to expand it.
notificationBuilder.setPriority(priority);
-
- // Add action buttons. Show at most three, using the following priority ordering:
- // 1. Map
- // 2. Call
- // 3. Email
- // 4. Snooze
- // Actions will only be shown if they are applicable; i.e. with no location, map will
- // not be shown, and with no recipients, snooze will not be shown.
- // TODO: Get icons, get strings. Maybe show preview of actual location/number?
- int numActions = 0;
- if (mapIntent != null && numActions < MAX_NOTIF_ACTIONS) {
- notificationBuilder.addAction(R.drawable.ic_map,
- resources.getString(R.string.map_label), mapIntent);
- numActions++;
- }
- if (callIntent != null && numActions < MAX_NOTIF_ACTIONS) {
- notificationBuilder.addAction(R.drawable.ic_call,
- resources.getString(R.string.call_label), callIntent);
- numActions++;
- }
- if (emailIntent != null && numActions < MAX_NOTIF_ACTIONS) {
- notificationBuilder.addAction(R.drawable.ic_menu_email_holo_dark,
- resources.getString(R.string.email_guests_label), emailIntent);
- numActions++;
- }
- if (snoozeIntent != null && numActions < MAX_NOTIF_ACTIONS) {
- notificationBuilder.addAction(R.drawable.ic_alarm_holo_dark,
- resources.getString(R.string.snooze_label), snoozeIntent);
- numActions++;
- }
- return notificationBuilder.getNotification();
-
- } else {
- // Old-style notification (pre-JB). Use custom view with buttons to provide
- // JB-like functionality (snooze/email).
- Notification n = notificationBuilder.getNotification();
-
- // Use custom view with buttons to provide JB-like functionality (snooze/email).
- RemoteViews contentView = new RemoteViews(context.getPackageName(),
- R.layout.notification);
- contentView.setImageViewResource(R.id.image, R.drawable.stat_notify_calendar);
- contentView.setTextViewText(R.id.title, title);
- contentView.setTextViewText(R.id.text, summaryText);
-
- int numActions = 0;
- if (mapIntent == null || numActions >= MAX_NOTIF_ACTIONS) {
- contentView.setViewVisibility(R.id.map_button, View.GONE);
- } else {
- contentView.setViewVisibility(R.id.map_button, View.VISIBLE);
- contentView.setOnClickPendingIntent(R.id.map_button, mapIntent);
- contentView.setViewVisibility(R.id.end_padding, View.GONE);
- numActions++;
- }
- if (callIntent == null || numActions >= MAX_NOTIF_ACTIONS) {
- contentView.setViewVisibility(R.id.call_button, View.GONE);
- } else {
- contentView.setViewVisibility(R.id.call_button, View.VISIBLE);
- contentView.setOnClickPendingIntent(R.id.call_button, callIntent);
- contentView.setViewVisibility(R.id.end_padding, View.GONE);
- numActions++;
- }
- if (emailIntent == null || numActions >= MAX_NOTIF_ACTIONS) {
- contentView.setViewVisibility(R.id.email_button, View.GONE);
- } else {
- contentView.setViewVisibility(R.id.email_button, View.VISIBLE);
- contentView.setOnClickPendingIntent(R.id.email_button, emailIntent);
- contentView.setViewVisibility(R.id.end_padding, View.GONE);
- numActions++;
- }
- if (snoozeIntent == null || numActions >= MAX_NOTIF_ACTIONS) {
- contentView.setViewVisibility(R.id.snooze_button, View.GONE);
- } else {
- contentView.setViewVisibility(R.id.snooze_button, View.VISIBLE);
- contentView.setOnClickPendingIntent(R.id.snooze_button, snoozeIntent);
- contentView.setViewVisibility(R.id.end_padding, View.GONE);
- numActions++;
- }
-
- n.contentView = contentView;
-
- return n;
- }
- }
-
- /**
- * Creates an expanding notification. The initial expanded state is decided by
- * the notification manager based on the priority.
- */
- public static NotificationWrapper makeExpandingNotification(Context context, String title,
- String summaryText, String description, long startMillis, long endMillis, long eventId,
- int notificationId, boolean doPopup, int priority) {
- Notification.Builder basicBuilder = new Notification.Builder(context);
- Notification notification = buildBasicNotification(basicBuilder, context, title,
- summaryText, startMillis, endMillis, eventId, notificationId, doPopup,
- priority, true);
- if (Utils.isJellybeanOrLater()) {
- // Create a new-style expanded notification
- Notification.BigTextStyle expandedBuilder = new Notification.BigTextStyle();
- if (description != null) {
- description = mBlankLinePattern.matcher(description).replaceAll("");
- description = description.trim();
- }
- CharSequence text;
- if (TextUtils.isEmpty(description)) {
- text = summaryText;
- } else {
- SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
- stringBuilder.append(summaryText);
- stringBuilder.append("\n\n");
- stringBuilder.setSpan(new RelativeSizeSpan(0.5f), summaryText.length(),
- stringBuilder.length(), 0);
- stringBuilder.append(description);
- text = stringBuilder;
- }
- expandedBuilder.bigText(text);
- basicBuilder.setStyle(expandedBuilder);
- notification = basicBuilder.build();
- }
- return new NotificationWrapper(notification, notificationId, eventId, startMillis,
- endMillis, doPopup);
- }
-
- /**
- * Creates an expanding digest notification for expired events.
- */
- public static NotificationWrapper makeDigestNotification(Context context,
- ArrayList<AlertService.NotificationInfo> notificationInfos, String digestTitle,
- boolean expandable) {
- if (notificationInfos == null || notificationInfos.size() < 1) {
- return null;
- }
-
- Resources res = context.getResources();
- int numEvents = notificationInfos.size();
- long[] eventIds = new long[notificationInfos.size()];
- long[] startMillis = new long[notificationInfos.size()];
- for (int i = 0; i < notificationInfos.size(); i++) {
- eventIds[i] = notificationInfos.get(i).eventId;
- startMillis[i] = notificationInfos.get(i).startMillis;
- }
-
- // Create an intent triggered by clicking on the status icon that shows the alerts list.
- PendingIntent pendingClickIntent = createAlertActivityIntent(context);
-
- // Create an intent triggered by dismissing the digest notification that clears all
- // expired events.
- Intent deleteIntent = new Intent();
- deleteIntent.setClass(context, DismissAlarmsService.class);
- deleteIntent.setAction(DismissAlarmsService.DISMISS_ACTION);
- deleteIntent.putExtra(AlertUtils.EVENT_IDS_KEY, eventIds);
- deleteIntent.putExtra(AlertUtils.EVENT_STARTS_KEY, startMillis);
- PendingIntent pendingDeleteIntent = PendingIntent.getService(context, 0, deleteIntent,
- PendingIntent.FLAG_UPDATE_CURRENT);
-
- if (digestTitle == null || digestTitle.length() == 0) {
- digestTitle = res.getString(R.string.no_title_label);
- }
-
- Notification.Builder notificationBuilder = new Notification.Builder(context);
- notificationBuilder.setContentText(digestTitle);
- notificationBuilder.setSmallIcon(R.drawable.stat_notify_calendar_multiple);
- notificationBuilder.setContentIntent(pendingClickIntent);
- notificationBuilder.setDeleteIntent(pendingDeleteIntent);
- String nEventsStr = res.getQuantityString(R.plurals.Nevents, numEvents, numEvents);
- notificationBuilder.setContentTitle(nEventsStr);
-
- Notification n;
- if (Utils.isJellybeanOrLater()) {
- // New-style notification...
-
- // Set to min priority to encourage the notification manager to collapse it.
- notificationBuilder.setPriority(Notification.PRIORITY_MIN);
-
- if (expandable) {
- // Multiple reminders. Combine into an expanded digest notification.
- Notification.InboxStyle expandedBuilder = new Notification.InboxStyle();
- int i = 0;
- for (AlertService.NotificationInfo info : notificationInfos) {
- if (i < NOTIFICATION_DIGEST_MAX_LENGTH) {
- String name = info.eventName;
- if (TextUtils.isEmpty(name)) {
- name = context.getResources().getString(R.string.no_title_label);
- }
- String timeLocation = AlertUtils.formatTimeLocation(context,
- info.startMillis, info.allDay, info.location);
-
- TextAppearanceSpan primaryTextSpan = new TextAppearanceSpan(context,
- R.style.NotificationPrimaryText);
- TextAppearanceSpan secondaryTextSpan = new TextAppearanceSpan(context,
- R.style.NotificationSecondaryText);
-
- // Event title in bold.
- SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
- stringBuilder.append(name);
- stringBuilder.setSpan(primaryTextSpan, 0, stringBuilder.length(), 0);
- stringBuilder.append(" ");
-
- // Followed by time and location.
- int secondaryIndex = stringBuilder.length();
- stringBuilder.append(timeLocation);
- stringBuilder.setSpan(secondaryTextSpan, secondaryIndex,
- stringBuilder.length(), 0);
- expandedBuilder.addLine(stringBuilder);
- i++;
- } else {
- break;
- }
- }
-
- // If there are too many to display, add "+X missed events" for the last line.
- int remaining = numEvents - i;
- if (remaining > 0) {
- String nMoreEventsStr = res.getQuantityString(R.plurals.N_remaining_events,
- remaining, remaining);
- // TODO: Add highlighting and icon to this last entry once framework allows it.
- expandedBuilder.setSummaryText(nMoreEventsStr);
- }
-
- // Remove the title in the expanded form (redundant with the listed items).
- expandedBuilder.setBigContentTitle("");
- notificationBuilder.setStyle(expandedBuilder);
- }
-
- n = notificationBuilder.build();
- } else {
- // Old-style notification (pre-JB). We only need a standard notification (no
- // buttons) but use a custom view so it is consistent with the others.
- n = notificationBuilder.getNotification();
-
- // Use custom view with buttons to provide JB-like functionality (snooze/email).
- RemoteViews contentView = new RemoteViews(context.getPackageName(),
- R.layout.notification);
- contentView.setImageViewResource(R.id.image, R.drawable.stat_notify_calendar_multiple);
- contentView.setTextViewText(R.id.title, nEventsStr);
- contentView.setTextViewText(R.id.text, digestTitle);
- contentView.setViewVisibility(R.id.time, View.VISIBLE);
- contentView.setViewVisibility(R.id.map_button, View.GONE);
- contentView.setViewVisibility(R.id.call_button, View.GONE);
- contentView.setViewVisibility(R.id.email_button, View.GONE);
- contentView.setViewVisibility(R.id.snooze_button, View.GONE);
- contentView.setViewVisibility(R.id.end_padding, View.VISIBLE);
- n.contentView = contentView;
-
- // Use timestamp to force expired digest notification to the bottom (there is no
- // priority setting before JB release). This is hidden by the custom view.
- n.when = 1;
- }
-
- NotificationWrapper nw = new NotificationWrapper(n);
- if (AlertService.DEBUG) {
- for (AlertService.NotificationInfo info : notificationInfos) {
- nw.add(new NotificationWrapper(null, 0, info.eventId, info.startMillis,
- info.endMillis, false));
- }
}
- return nw;
+ return notificationBuilder.getNotification();
}
private void closeNotificationShade(Context context) {
Intent closeNotificationShadeIntent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
context.sendBroadcast(closeNotificationShadeIntent);
}
-
- private static final String[] ATTENDEES_PROJECTION = new String[] {
- Attendees.ATTENDEE_EMAIL, // 0
- Attendees.ATTENDEE_STATUS, // 1
- };
- private static final int ATTENDEES_INDEX_EMAIL = 0;
- private static final int ATTENDEES_INDEX_STATUS = 1;
- private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=?";
- private static final String ATTENDEES_SORT_ORDER = Attendees.ATTENDEE_NAME + " ASC, "
- + Attendees.ATTENDEE_EMAIL + " ASC";
-
- private static final String[] EVENT_PROJECTION = new String[] {
- Calendars.OWNER_ACCOUNT, // 0
- Calendars.ACCOUNT_NAME, // 1
- Events.TITLE, // 2
- Events.ORGANIZER, // 3
- };
- private static final int EVENT_INDEX_OWNER_ACCOUNT = 0;
- private static final int EVENT_INDEX_ACCOUNT_NAME = 1;
- private static final int EVENT_INDEX_TITLE = 2;
- private static final int EVENT_INDEX_ORGANIZER = 3;
-
- private static Cursor getEventCursor(Context context, long eventId) {
- return context.getContentResolver().query(
- ContentUris.withAppendedId(Events.CONTENT_URI, eventId), EVENT_PROJECTION,
- null, null, null);
- }
-
- private static Cursor getAttendeesCursor(Context context, long eventId) {
- return context.getContentResolver().query(Attendees.CONTENT_URI,
- ATTENDEES_PROJECTION, ATTENDEES_WHERE, new String[] { Long.toString(eventId) },
- ATTENDEES_SORT_ORDER);
- }
-
- private static Cursor getLocationCursor(Context context, long eventId) {
- return context.getContentResolver().query(
- ContentUris.withAppendedId(Events.CONTENT_URI, eventId),
- new String[] { Events.EVENT_LOCATION }, null, null, null);
- }
-
- /**
- * Creates a broadcast pending intent that fires to AlertReceiver when the email button
- * is clicked.
- */
- private static PendingIntent createBroadcastMailIntent(Context context, long eventId,
- String eventTitle) {
- // Query for viewer account.
- String syncAccount = null;
- Cursor eventCursor = getEventCursor(context, eventId);
- try {
- if (eventCursor != null && eventCursor.moveToFirst()) {
- syncAccount = eventCursor.getString(EVENT_INDEX_ACCOUNT_NAME);
- }
- } finally {
- if (eventCursor != null) {
- eventCursor.close();
- }
- }
-
- // Query attendees to see if there are any to email.
- Cursor attendeesCursor = getAttendeesCursor(context, eventId);
- try {
- if (attendeesCursor != null && attendeesCursor.moveToFirst()) {
- do {
- String email = attendeesCursor.getString(ATTENDEES_INDEX_EMAIL);
- if (Utils.isEmailableFrom(email, syncAccount)) {
- Intent broadcastIntent = new Intent(MAIL_ACTION);
- broadcastIntent.setClass(context, AlertReceiver.class);
- broadcastIntent.putExtra(EXTRA_EVENT_ID, eventId);
- return PendingIntent.getBroadcast(context,
- Long.valueOf(eventId).hashCode(), broadcastIntent,
- PendingIntent.FLAG_CANCEL_CURRENT);
- }
- } while (attendeesCursor.moveToNext());
- }
- return null;
-
- } finally {
- if (attendeesCursor != null) {
- attendeesCursor.close();
- }
- }
- }
-
- /**
- * Creates an Intent for emailing the attendees of the event. Returns null if there
- * are no emailable attendees.
- */
- static Intent createEmailIntent(Context context, long eventId, String body) {
- // TODO: Refactor to move query part into Utils.createEmailAttendeeIntent, to
- // be shared with EventInfoFragment.
-
- // Query for the owner account(s).
- String ownerAccount = null;
- String syncAccount = null;
- String eventTitle = null;
- String eventOrganizer = null;
- Cursor eventCursor = getEventCursor(context, eventId);
- try {
- if (eventCursor != null && eventCursor.moveToFirst()) {
- ownerAccount = eventCursor.getString(EVENT_INDEX_OWNER_ACCOUNT);
- syncAccount = eventCursor.getString(EVENT_INDEX_ACCOUNT_NAME);
- eventTitle = eventCursor.getString(EVENT_INDEX_TITLE);
- eventOrganizer = eventCursor.getString(EVENT_INDEX_ORGANIZER);
- }
- } finally {
- if (eventCursor != null) {
- eventCursor.close();
- }
- }
- if (TextUtils.isEmpty(eventTitle)) {
- eventTitle = context.getResources().getString(R.string.no_title_label);
- }
-
- // Query for the attendees.
- List<String> toEmails = new ArrayList<String>();
- List<String> ccEmails = new ArrayList<String>();
- Cursor attendeesCursor = getAttendeesCursor(context, eventId);
- try {
- if (attendeesCursor != null && attendeesCursor.moveToFirst()) {
- do {
- int status = attendeesCursor.getInt(ATTENDEES_INDEX_STATUS);
- String email = attendeesCursor.getString(ATTENDEES_INDEX_EMAIL);
- switch(status) {
- case Attendees.ATTENDEE_STATUS_DECLINED:
- addIfEmailable(ccEmails, email, syncAccount);
- break;
- default:
- addIfEmailable(toEmails, email, syncAccount);
- }
- } while (attendeesCursor.moveToNext());
- }
- } finally {
- if (attendeesCursor != null) {
- attendeesCursor.close();
- }
- }
-
- // Add organizer only if no attendees to email (the case when too many attendees
- // in the event to sync or show).
- if (toEmails.size() == 0 && ccEmails.size() == 0 && eventOrganizer != null) {
- addIfEmailable(toEmails, eventOrganizer, syncAccount);
- }
-
- Intent intent = null;
- if (ownerAccount != null && (toEmails.size() > 0 || ccEmails.size() > 0)) {
- intent = Utils.createEmailAttendeesIntent(context.getResources(), eventTitle, body,
- toEmails, ccEmails, ownerAccount);
- }
-
- if (intent == null) {
- return null;
- }
- else {
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- return intent;
- }
- }
-
- private static void addIfEmailable(List<String> emailList, String email, String syncAccount) {
- if (Utils.isEmailableFrom(email, syncAccount)) {
- emailList.add(email);
- }
- }
-
- /**
- * Using the linkify magic, get a list of URLs from the event's location. If no such links
- * are found, we should end up with a single geo link of the entire string.
- */
- private static URLSpan[] getURLSpans(Context context, long eventId) {
- Cursor locationCursor = getLocationCursor(context, eventId);
-
- // Default to empty list
- URLSpan[] urlSpans = new URLSpan[0];
- if (locationCursor != null && locationCursor.moveToFirst()) {
- String location = locationCursor.getString(0); // Only one item in this cursor.
- if (location != null && !location.isEmpty()) {
- Spannable text = Utils.extendedLinkify(location, true);
- // The linkify method should have found at least one link, at the very least.
- // If no smart links were found, it should have set the whole string as a geo link.
- urlSpans = text.getSpans(0, text.length(), URLSpan.class);
- }
- locationCursor.close();
- }
-
- return urlSpans;
- }
-
- /**
- * Create a pending intent to send ourself a broadcast to start maps, using the first map
- * link available.
- * If no links are found, return null.
- */
- private static PendingIntent createMapBroadcastIntent(Context context, URLSpan[] urlSpans,
- long eventId) {
- for (int span_i = 0; span_i < urlSpans.length; span_i++) {
- URLSpan urlSpan = urlSpans[span_i];
- String urlString = urlSpan.getURL();
- if (urlString.startsWith(GEO_PREFIX)) {
- Intent broadcastIntent = new Intent(MAP_ACTION);
- broadcastIntent.setClass(context, AlertReceiver.class);
- broadcastIntent.putExtra(EXTRA_EVENT_ID, eventId);
- return PendingIntent.getBroadcast(context,
- Long.valueOf(eventId).hashCode(), broadcastIntent,
- PendingIntent.FLAG_CANCEL_CURRENT);
- }
- }
-
- // No geo link was found, so return null;
- return null;
- }
-
- /**
- * Create an intent to take the user to maps, using the first map link available.
- * If no links are found, return null.
- */
- private static Intent createMapActivityIntent(Context context, URLSpan[] urlSpans) {
- for (int span_i = 0; span_i < urlSpans.length; span_i++) {
- URLSpan urlSpan = urlSpans[span_i];
- String urlString = urlSpan.getURL();
- if (urlString.startsWith(GEO_PREFIX)) {
- Intent geoIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlString));
- geoIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- return geoIntent;
- }
- }
-
- // No geo link was found, so return null;
- return null;
- }
-
- /**
- * Create a pending intent to send ourself a broadcast to take the user to dialer, or any other
- * app capable of making phone calls. Use the first phone number available. If no phone number
- * is found, or if the device is not capable of making phone calls (i.e. a tablet), return null.
- */
- private static PendingIntent createCallBroadcastIntent(Context context, URLSpan[] urlSpans,
- long eventId) {
- // Return null if the device is unable to make phone calls.
- TelephonyManager tm =
- (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_NONE) {
- return null;
- }
-
- for (int span_i = 0; span_i < urlSpans.length; span_i++) {
- URLSpan urlSpan = urlSpans[span_i];
- String urlString = urlSpan.getURL();
- if (urlString.startsWith(TEL_PREFIX)) {
- Intent broadcastIntent = new Intent(CALL_ACTION);
- broadcastIntent.setClass(context, AlertReceiver.class);
- broadcastIntent.putExtra(EXTRA_EVENT_ID, eventId);
- return PendingIntent.getBroadcast(context,
- Long.valueOf(eventId).hashCode(), broadcastIntent,
- PendingIntent.FLAG_CANCEL_CURRENT);
- }
- }
-
- // No tel link was found, so return null;
- return null;
- }
-
- /**
- * Create an intent to take the user to dialer, or any other app capable of making phone calls.
- * Use the first phone number available. If no phone number is found, or if the device is
- * not capable of making phone calls (i.e. a tablet), return null.
- */
- private static Intent createCallActivityIntent(Context context, URLSpan[] urlSpans) {
- // Return null if the device is unable to make phone calls.
- TelephonyManager tm =
- (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_NONE) {
- return null;
- }
-
- for (int span_i = 0; span_i < urlSpans.length; span_i++) {
- URLSpan urlSpan = urlSpans[span_i];
- String urlString = urlSpan.getURL();
- if (urlString.startsWith(TEL_PREFIX)) {
- Intent callIntent = new Intent(Intent.ACTION_DIAL, Uri.parse(urlString));
- callIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- return callIntent;
- }
- }
-
- // No tel link was found, so return null;
- return null;
- }
}
diff --git a/src/com/android/calendar/alerts/AlertService.java b/src/com/android/calendar/alerts/AlertService.java
index ecd85723..d2c994da 100644
--- a/src/com/android/calendar/alerts/AlertService.java
+++ b/src/com/android/calendar/alerts/AlertService.java
@@ -42,8 +42,6 @@ import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.Log;
-import com.android.calendar.GeneralPreferences;
-import com.android.calendar.OtherPreferences;
import com.android.calendar.R;
import com.android.calendar.Utils;
@@ -60,7 +58,6 @@ public class AlertService extends Service {
private static final String TAG = "AlertService";
private volatile Looper mServiceLooper;
- private volatile ServiceHandler mServiceHandler;
static final String[] ALERT_PROJECTION = new String[] {
CalendarAlerts._ID, // 0
@@ -111,15 +108,6 @@ public class AlertService extends Service {
// Hard limit to the number of notifications displayed.
public static final int MAX_NOTIFICATIONS = 20;
- // Shared prefs key for storing whether the EVENT_REMINDER event from the provider
- // was ever received. Some OEMs modified this provider broadcast, so we had to
- // do the alarm scheduling here in the app, for the unbundled app's reminders to work.
- // If the EVENT_REMINDER event was ever received, we know we can skip our secondary
- // alarm scheduling.
- private static final String PROVIDER_REMINDER_PREF_KEY =
- "preference_received_provider_reminder_broadcast";
- private static Boolean sReceivedProviderReminderBroadcast = null;
-
// Added wrapper for testing
public static class NotificationWrapper {
Notification mNotification;
@@ -170,740 +158,6 @@ public class AlertService extends Service {
}
}
- void processMessage(Message msg) {
- Bundle bundle = (Bundle) msg.obj;
-
- // On reboot, update the notification bar with the contents of the
- // CalendarAlerts table.
- String action = bundle.getString("action");
- if (DEBUG) {
- Log.d(TAG, bundle.getLong(android.provider.CalendarContract.CalendarAlerts.ALARM_TIME)
- + " Action = " + action);
- }
-
- // Some OEMs had changed the provider's EVENT_REMINDER broadcast to their own event,
- // which broke our unbundled app's reminders. So we added backup alarm scheduling to the
- // app, but we know we can turn it off if we ever receive the EVENT_REMINDER broadcast.
- boolean providerReminder = action.equals(
- android.provider.CalendarContract.ACTION_EVENT_REMINDER);
- if (providerReminder) {
- if (sReceivedProviderReminderBroadcast == null) {
- sReceivedProviderReminderBroadcast = Utils.getSharedPreference(this,
- PROVIDER_REMINDER_PREF_KEY, false);
- }
-
- if (!sReceivedProviderReminderBroadcast) {
- sReceivedProviderReminderBroadcast = true;
- Log.d(TAG, "Setting key " + PROVIDER_REMINDER_PREF_KEY + " to: true");
- Utils.setSharedPreference(this, PROVIDER_REMINDER_PREF_KEY, true);
- }
- }
-
- if (providerReminder ||
- action.equals(Intent.ACTION_PROVIDER_CHANGED) ||
- action.equals(android.provider.CalendarContract.ACTION_EVENT_REMINDER) ||
- action.equals(AlertReceiver.EVENT_REMINDER_APP_ACTION) ||
- action.equals(Intent.ACTION_LOCALE_CHANGED)) {
-
- // b/7652098: Add a delay after the provider-changed event before refreshing
- // notifications to help issue with the unbundled app installed on HTC having
- // stale notifications.
- if (action.equals(Intent.ACTION_PROVIDER_CHANGED)) {
- try {
- Thread.sleep(5000);
- } catch (Exception e) {
- // Ignore.
- }
- }
-
- // If we dismissed a notification for a new event, then we need to sync the cache when
- // an ACTION_PROVIDER_CHANGED event has been sent. Unfortunately, the data provider
- // has a delay of CalendarProvider2.SYNC_UPDATE_BROADCAST_TIMEOUT_MILLIS (ie. 30 sec.)
- // until it notifies us that the sync adapter has finished.
- // TODO(psliwowski): Find a quicker way to be notified when the data provider has the
- // syncId for event.
- GlobalDismissManager.syncSenderDismissCache(this);
- updateAlertNotification(this);
- } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
- // The provider usually initiates this setting up of alarms on startup,
- // but there was a bug (b/7221716) where a race condition caused this step to be
- // skipped, resulting in missed alarms. This is a stopgap to minimize this bug
- // for devices that don't have the provider fix, by initiating this a 2nd time here.
- // However, it would still theoretically be possible to hit the race condition
- // the 2nd time and still miss alarms.
- //
- // TODO: Remove this when the provider fix is rolled out everywhere.
- Intent intent = new Intent();
- intent.setClass(this, InitAlarmsService.class);
- startService(intent);
- } else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
- doTimeChanged();
- } else if (action.equals(AlertReceiver.ACTION_DISMISS_OLD_REMINDERS)) {
- dismissOldAlerts(this);
- } else {
- Log.w(TAG, "Invalid action: " + action);
- }
-
- // Schedule the alarm for the next upcoming reminder, if not done by the provider.
- if (sReceivedProviderReminderBroadcast == null || !sReceivedProviderReminderBroadcast) {
- Log.d(TAG, "Scheduling next alarm with AlarmScheduler. "
- + "sEventReminderReceived: " + sReceivedProviderReminderBroadcast);
- AlarmScheduler.scheduleNextAlarm(this);
- }
- }
-
- static void dismissOldAlerts(Context context) {
- ContentResolver cr = context.getContentResolver();
- final long currentTime = System.currentTimeMillis();
- ContentValues vals = new ContentValues();
- vals.put(CalendarAlerts.STATE, CalendarAlerts.STATE_DISMISSED);
- cr.update(CalendarAlerts.CONTENT_URI, vals, DISMISS_OLD_SELECTION, new String[] {
- Long.toString(currentTime), Integer.toString(CalendarAlerts.STATE_SCHEDULED)
- });
- }
-
- static boolean updateAlertNotification(Context context) {
- ContentResolver cr = context.getContentResolver();
- NotificationMgr nm = new NotificationMgrWrapper(
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE));
- final long currentTime = System.currentTimeMillis();
- SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
-
- if (DEBUG) {
- Log.d(TAG, "Beginning updateAlertNotification");
- }
-
- if (!prefs.getBoolean(GeneralPreferences.KEY_ALERTS, true)) {
- if (DEBUG) {
- Log.d(TAG, "alert preference is OFF");
- }
-
- // If we shouldn't be showing notifications cancel any existing ones
- // and return.
- nm.cancelAll();
- return true;
- }
-
- // Sync CalendarAlerts with global dismiss cache before query it
- GlobalDismissManager.syncReceiverDismissCache(context);
- Cursor alertCursor = cr.query(CalendarAlerts.CONTENT_URI, ALERT_PROJECTION,
- (ACTIVE_ALERTS_SELECTION + currentTime), ACTIVE_ALERTS_SELECTION_ARGS,
- ACTIVE_ALERTS_SORT);
-
- if (alertCursor == null || alertCursor.getCount() == 0) {
- if (alertCursor != null) {
- alertCursor.close();
- }
-
- if (DEBUG) Log.d(TAG, "No fired or scheduled alerts");
- nm.cancelAll();
- return false;
- }
-
- return generateAlerts(context, nm, AlertUtils.createAlarmManager(context), prefs,
- alertCursor, currentTime, MAX_NOTIFICATIONS);
- }
-
- public static boolean generateAlerts(Context context, NotificationMgr nm,
- AlarmManagerInterface alarmMgr, SharedPreferences prefs, Cursor alertCursor,
- final long currentTime, final int maxNotifications) {
- if (DEBUG) {
- Log.d(TAG, "alertCursor count:" + alertCursor.getCount());
- }
-
- // Process the query results and bucketize events.
- ArrayList<NotificationInfo> highPriorityEvents = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> mediumPriorityEvents = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> lowPriorityEvents = new ArrayList<NotificationInfo>();
- int numFired = processQuery(alertCursor, context, currentTime, highPriorityEvents,
- mediumPriorityEvents, lowPriorityEvents);
-
- if (highPriorityEvents.size() + mediumPriorityEvents.size()
- + lowPriorityEvents.size() == 0) {
- nm.cancelAll();
- return true;
- }
-
- long nextRefreshTime = Long.MAX_VALUE;
- int currentNotificationId = 1;
- NotificationPrefs notificationPrefs = new NotificationPrefs(context, prefs,
- (numFired == 0));
-
- // If there are more high/medium priority events than we can show, bump some to
- // the low priority digest.
- redistributeBuckets(highPriorityEvents, mediumPriorityEvents, lowPriorityEvents,
- maxNotifications);
-
- // Post the individual higher priority events (future and recently started
- // concurrent events). Order these so that earlier start times appear higher in
- // the notification list.
- for (int i = 0; i < highPriorityEvents.size(); i++) {
- NotificationInfo info = highPriorityEvents.get(i);
- String summaryText = AlertUtils.formatTimeLocation(context, info.startMillis,
- info.allDay, info.location);
- postNotification(info, summaryText, context, true, notificationPrefs, nm,
- currentNotificationId++);
-
- // Keep concurrent events high priority (to appear higher in the notification list)
- // until 15 minutes into the event.
- nextRefreshTime = Math.min(nextRefreshTime, getNextRefreshTime(info, currentTime));
- }
-
- // Post the medium priority events (concurrent events that started a while ago).
- // Order these so more recent start times appear higher in the notification list.
- //
- // TODO: Post these with the same notification priority level as the higher priority
- // events, so that all notifications will be co-located together.
- for (int i = mediumPriorityEvents.size() - 1; i >= 0; i--) {
- NotificationInfo info = mediumPriorityEvents.get(i);
- // TODO: Change to a relative time description like: "Started 40 minutes ago".
- // This requires constant refreshing to the message as time goes.
- String summaryText = AlertUtils.formatTimeLocation(context, info.startMillis,
- info.allDay, info.location);
- postNotification(info, summaryText, context, false, notificationPrefs, nm,
- currentNotificationId++);
-
- // Refresh when concurrent event ends so it will drop into the expired digest.
- nextRefreshTime = Math.min(nextRefreshTime, getNextRefreshTime(info, currentTime));
- }
-
- // Post the low priority events as 1 combined notification.
- int numLowPriority = lowPriorityEvents.size();
- if (numLowPriority > 0) {
- String expiredDigestTitle = getDigestTitle(lowPriorityEvents);
- NotificationWrapper notification;
- if (numLowPriority == 1) {
- // If only 1 expired event, display an "old-style" basic alert.
- NotificationInfo info = lowPriorityEvents.get(0);
- String summaryText = AlertUtils.formatTimeLocation(context, info.startMillis,
- info.allDay, info.location);
- notification = AlertReceiver.makeBasicNotification(context, info.eventName,
- summaryText, info.startMillis, info.endMillis, info.eventId,
- AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID, false,
- Notification.PRIORITY_MIN);
- } else {
- // Multiple expired events are listed in a digest.
- notification = AlertReceiver.makeDigestNotification(context,
- lowPriorityEvents, expiredDigestTitle, false);
- }
-
- // Add options for a quiet update.
- addNotificationOptions(notification, true, expiredDigestTitle,
- notificationPrefs.getDefaultVibrate(),
- notificationPrefs.getRingtoneAndSilence(),
- false); /* Do not show the LED for the expired events. */
-
- if (DEBUG) {
- Log.d(TAG, "Quietly posting digest alarm notification, numEvents:" + numLowPriority
- + ", notificationId:" + AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID);
- }
-
- // Post the new notification for the group.
- nm.notify(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID, notification);
- } else {
- nm.cancel(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID);
- if (DEBUG) {
- Log.d(TAG, "No low priority events, canceling the digest notification.");
- }
- }
-
- // Remove the notifications that are hanging around from the previous refresh.
- if (currentNotificationId <= maxNotifications) {
- nm.cancelAllBetween(currentNotificationId, maxNotifications);
- if (DEBUG) {
- Log.d(TAG, "Canceling leftover notification IDs " + currentNotificationId + "-"
- + maxNotifications);
- }
- }
-
- // Schedule the next silent refresh time so notifications will change
- // buckets (eg. drop into expired digest, etc).
- if (nextRefreshTime < Long.MAX_VALUE && nextRefreshTime > currentTime) {
- AlertUtils.scheduleNextNotificationRefresh(context, alarmMgr, nextRefreshTime);
- if (DEBUG) {
- long minutesBeforeRefresh = (nextRefreshTime - currentTime) / MINUTE_MS;
- Time time = new Time();
- time.set(nextRefreshTime);
- String msg = String.format("Scheduling next notification refresh in %d min at: "
- + "%d:%02d", minutesBeforeRefresh, time.hour, time.minute);
- Log.d(TAG, msg);
- }
- } else if (nextRefreshTime < currentTime) {
- Log.e(TAG, "Illegal state: next notification refresh time found to be in the past.");
- }
-
- // Flushes old fired alerts from internal storage, if needed.
- AlertUtils.flushOldAlertsFromInternalStorage(context);
-
- return true;
- }
-
- /**
- * Redistributes events in the priority lists based on the max # of notifications we
- * can show.
- */
- static void redistributeBuckets(ArrayList<NotificationInfo> highPriorityEvents,
- ArrayList<NotificationInfo> mediumPriorityEvents,
- ArrayList<NotificationInfo> lowPriorityEvents, int maxNotifications) {
-
- // If too many high priority alerts, shift the remaining high priority and all the
- // medium priority ones to the low priority bucket. Note that order is important
- // here; these lists are sorted by descending start time. Maintain that ordering
- // so posted notifications are in the expected order.
- if (highPriorityEvents.size() > maxNotifications) {
- // Move mid-priority to the digest.
- lowPriorityEvents.addAll(0, mediumPriorityEvents);
-
- // Move the rest of the high priority ones (latest ones) to the digest.
- List<NotificationInfo> itemsToMoveSublist = highPriorityEvents.subList(
- 0, highPriorityEvents.size() - maxNotifications);
- // TODO: What order for high priority in the digest?
- lowPriorityEvents.addAll(0, itemsToMoveSublist);
- if (DEBUG) {
- logEventIdsBumped(mediumPriorityEvents, itemsToMoveSublist);
- }
- mediumPriorityEvents.clear();
- // Clearing the sublist view removes the items from the highPriorityEvents list.
- itemsToMoveSublist.clear();
- }
-
- // Bump the medium priority events if necessary.
- if (mediumPriorityEvents.size() + highPriorityEvents.size() > maxNotifications) {
- int spaceRemaining = maxNotifications - highPriorityEvents.size();
-
- // Reached our max, move the rest to the digest. Since these are concurrent
- // events, we move the ones with the earlier start time first since they are
- // further in the past and less important.
- List<NotificationInfo> itemsToMoveSublist = mediumPriorityEvents.subList(
- spaceRemaining, mediumPriorityEvents.size());
- lowPriorityEvents.addAll(0, itemsToMoveSublist);
- if (DEBUG) {
- logEventIdsBumped(itemsToMoveSublist, null);
- }
-
- // Clearing the sublist view removes the items from the mediumPriorityEvents list.
- itemsToMoveSublist.clear();
- }
- }
-
- private static void logEventIdsBumped(List<NotificationInfo> list1,
- List<NotificationInfo> list2) {
- StringBuilder ids = new StringBuilder();
- if (list1 != null) {
- for (NotificationInfo info : list1) {
- ids.append(info.eventId);
- ids.append(",");
- }
- }
- if (list2 != null) {
- for (NotificationInfo info : list2) {
- ids.append(info.eventId);
- ids.append(",");
- }
- }
- if (ids.length() > 0 && ids.charAt(ids.length() - 1) == ',') {
- ids.setLength(ids.length() - 1);
- }
- if (ids.length() > 0) {
- Log.d(TAG, "Reached max postings, bumping event IDs {" + ids.toString()
- + "} to digest.");
- }
- }
-
- private static long getNextRefreshTime(NotificationInfo info, long currentTime) {
- long startAdjustedForAllDay = info.startMillis;
- long endAdjustedForAllDay = info.endMillis;
- if (info.allDay) {
- Time t = new Time();
- startAdjustedForAllDay = Utils.convertAlldayUtcToLocal(t, info.startMillis,
- Time.getCurrentTimezone());
- endAdjustedForAllDay = Utils.convertAlldayUtcToLocal(t, info.startMillis,
- Time.getCurrentTimezone());
- }
-
- // We change an event's priority bucket at 15 minutes into the event or 1/4 event duration.
- long nextRefreshTime = Long.MAX_VALUE;
- long gracePeriodCutoff = startAdjustedForAllDay +
- getGracePeriodMs(startAdjustedForAllDay, endAdjustedForAllDay, info.allDay);
- if (gracePeriodCutoff > currentTime) {
- nextRefreshTime = Math.min(nextRefreshTime, gracePeriodCutoff);
- }
-
- // ... and at the end (so expiring ones drop into a digest).
- if (endAdjustedForAllDay > currentTime && endAdjustedForAllDay > gracePeriodCutoff) {
- nextRefreshTime = Math.min(nextRefreshTime, endAdjustedForAllDay);
- }
- return nextRefreshTime;
- }
-
- /**
- * Processes the query results and bucketizes the alerts.
- *
- * @param highPriorityEvents This will contain future events, and concurrent events
- * that started recently (less than the interval DEPRIORITIZE_GRACE_PERIOD_MS).
- * @param mediumPriorityEvents This will contain concurrent events that started
- * more than DEPRIORITIZE_GRACE_PERIOD_MS ago.
- * @param lowPriorityEvents Will contain events that have ended.
- * @return Returns the number of new alerts to fire. If this is 0, it implies
- * a quiet update.
- */
- static int processQuery(final Cursor alertCursor, final Context context,
- final long currentTime, ArrayList<NotificationInfo> highPriorityEvents,
- ArrayList<NotificationInfo> mediumPriorityEvents,
- ArrayList<NotificationInfo> lowPriorityEvents) {
- // Experimental reminder setting to only remind for events that have
- // been responded to with "yes" or "maybe".
- String skipRemindersPref = Utils.getSharedPreference(context,
- OtherPreferences.KEY_OTHER_REMINDERS_RESPONDED, "");
- // Skip no-response events if the "Skip Reminders" preference has the second option,
- // "If declined or not responded", is selected.
- // Note that by default, the first option will be selected, so this will be false.
- boolean remindRespondedOnly = skipRemindersPref.equals(context.getResources().
- getStringArray(R.array.preferences_skip_reminders_values)[1]);
- // Experimental reminder setting to silence reminders when they are
- // during the pre-defined quiet hours.
- boolean useQuietHours = Utils.getSharedPreference(context,
- OtherPreferences.KEY_OTHER_QUIET_HOURS, false);
- // Note that the start time may be either before or after the end time,
- // depending on whether quiet hours cross through midnight.
- int quietHoursStartHour =
- OtherPreferences.QUIET_HOURS_DEFAULT_START_HOUR;
- int quietHoursStartMinute =
- OtherPreferences.QUIET_HOURS_DEFAULT_START_MINUTE;
- int quietHoursEndHour =
- OtherPreferences.QUIET_HOURS_DEFAULT_END_HOUR;
- int quietHoursEndMinute =
- OtherPreferences.QUIET_HOURS_DEFAULT_END_MINUTE;
- if (useQuietHours) {
- quietHoursStartHour = Utils.getSharedPreference(context,
- OtherPreferences.KEY_OTHER_QUIET_HOURS_START_HOUR,
- OtherPreferences.QUIET_HOURS_DEFAULT_START_HOUR);
- quietHoursStartMinute = Utils.getSharedPreference(context,
- OtherPreferences.KEY_OTHER_QUIET_HOURS_START_MINUTE,
- OtherPreferences.QUIET_HOURS_DEFAULT_START_MINUTE);
- quietHoursEndHour = Utils.getSharedPreference(context,
- OtherPreferences.KEY_OTHER_QUIET_HOURS_END_HOUR,
- OtherPreferences.QUIET_HOURS_DEFAULT_END_HOUR);
- quietHoursEndMinute = Utils.getSharedPreference(context,
- OtherPreferences.KEY_OTHER_QUIET_HOURS_END_MINUTE,
- OtherPreferences.QUIET_HOURS_DEFAULT_END_MINUTE);
- }
- Time time = new Time();
-
- ContentResolver cr = context.getContentResolver();
- HashMap<Long, NotificationInfo> eventIds = new HashMap<Long, NotificationInfo>();
- int numFired = 0;
- try {
- while (alertCursor.moveToNext()) {
- final long alertId = alertCursor.getLong(ALERT_INDEX_ID);
- final long eventId = alertCursor.getLong(ALERT_INDEX_EVENT_ID);
- final int minutes = alertCursor.getInt(ALERT_INDEX_MINUTES);
- final String eventName = alertCursor.getString(ALERT_INDEX_TITLE);
- final String description = alertCursor.getString(ALERT_INDEX_DESCRIPTION);
- final String location = alertCursor.getString(ALERT_INDEX_EVENT_LOCATION);
- final int status = alertCursor.getInt(ALERT_INDEX_SELF_ATTENDEE_STATUS);
- final boolean declined = status == Attendees.ATTENDEE_STATUS_DECLINED;
- final boolean responded = status != Attendees.ATTENDEE_STATUS_NONE
- && status != Attendees.ATTENDEE_STATUS_INVITED;
- final long beginTime = alertCursor.getLong(ALERT_INDEX_BEGIN);
- final long endTime = alertCursor.getLong(ALERT_INDEX_END);
- final Uri alertUri = ContentUris
- .withAppendedId(CalendarAlerts.CONTENT_URI, alertId);
- final long alarmTime = alertCursor.getLong(ALERT_INDEX_ALARM_TIME);
- boolean forceQuiet = false;
- if (useQuietHours) {
- // Quiet hours have been set.
- time.set(alarmTime);
- // Check whether the alarm will fire after the quiet hours
- // start time and/or before the quiet hours end time.
- boolean alarmAfterQuietHoursStart =
- (time.hour > quietHoursStartHour ||
- (time.hour == quietHoursStartHour
- && time.minute >= quietHoursStartMinute));
- boolean alarmBeforeQuietHoursEnd =
- (time.hour < quietHoursEndHour ||
- (time.hour == quietHoursEndHour
- && time.minute <= quietHoursEndMinute));
- // Check if quiet hours crosses through midnight, iff:
- // start hour is after end hour, or
- // start hour is equal to end hour, and start minute is
- // after end minute.
- // i.e. 22:30 - 06:45; 12:45 - 12:00
- // 01:05 - 10:30; 05:00 - 05:30
- boolean quietHoursCrossesMidnight =
- quietHoursStartHour > quietHoursEndHour ||
- (quietHoursStartHour == quietHoursEndHour
- && quietHoursStartMinute > quietHoursEndMinute);
- if (quietHoursCrossesMidnight) {
- // Quiet hours crosses midnight. Alarm should be quiet
- // if it's after start time OR before end time.
- if (alarmAfterQuietHoursStart ||
- alarmBeforeQuietHoursEnd) {
- forceQuiet = true;
- }
- } else {
- // Quiet hours doesn't cross midnight. Alarm should be
- // quiet if it's after start time AND before end time.
- if (alarmAfterQuietHoursStart &&
- alarmBeforeQuietHoursEnd) {
- forceQuiet = true;
- }
- }
- }
- int state = alertCursor.getInt(ALERT_INDEX_STATE);
- final boolean allDay = alertCursor.getInt(ALERT_INDEX_ALL_DAY) != 0;
-
- // Use app local storage to keep track of fired alerts to fix problem of multiple
- // installed calendar apps potentially causing missed alarms.
- boolean newAlertOverride = false;
- if (AlertUtils.BYPASS_DB && ((currentTime - alarmTime) / MINUTE_MS < 1)) {
- // To avoid re-firing alerts, only fire if alarmTime is very recent. Otherwise
- // we can get refires for non-dismissed alerts after app installation, or if the
- // SharedPrefs was cleared too early. This means alerts that were timed while
- // the phone was off may show up silently in the notification bar.
- boolean alreadyFired = AlertUtils.hasAlertFiredInSharedPrefs(context, eventId,
- beginTime, alarmTime);
- if (!alreadyFired) {
- newAlertOverride = true;
- }
- }
-
- if (DEBUG) {
- StringBuilder msgBuilder = new StringBuilder();
- msgBuilder.append("alertCursor result: alarmTime:").append(alarmTime)
- .append(" alertId:").append(alertId)
- .append(" eventId:").append(eventId)
- .append(" state: ").append(state)
- .append(" minutes:").append(minutes)
- .append(" declined:").append(declined)
- .append(" responded:").append(responded)
- .append(" beginTime:").append(beginTime)
- .append(" endTime:").append(endTime)
- .append(" allDay:").append(allDay)
- .append(" alarmTime:").append(alarmTime)
- .append(" forceQuiet:").append(forceQuiet);
- if (AlertUtils.BYPASS_DB) {
- msgBuilder.append(" newAlertOverride: " + newAlertOverride);
- }
- Log.d(TAG, msgBuilder.toString());
- }
-
- ContentValues values = new ContentValues();
- int newState = -1;
- boolean newAlert = false;
-
- // Uncomment for the behavior of clearing out alerts after the
- // events ended. b/1880369
- //
- // if (endTime < currentTime) {
- // newState = CalendarAlerts.DISMISSED;
- // } else
-
- // Remove declined events
- boolean sendAlert = !declined;
- // Check for experimental reminder settings.
- if (remindRespondedOnly) {
- // If the experimental setting is turned on, then only send
- // the alert if you've responded to the event.
- sendAlert = sendAlert && responded;
- }
- if (sendAlert) {
- if (state == CalendarAlerts.STATE_SCHEDULED || newAlertOverride) {
- newState = CalendarAlerts.STATE_FIRED;
- numFired++;
- // If quiet hours are forcing the alarm to be silent,
- // keep newAlert as false so it will not make noise.
- if (!forceQuiet) {
- newAlert = true;
- }
-
- // Record the received time in the CalendarAlerts table.
- // This is useful for finding bugs that cause alarms to be
- // missed or delayed.
- values.put(CalendarAlerts.RECEIVED_TIME, currentTime);
- }
- } else {
- newState = CalendarAlerts.STATE_DISMISSED;
- }
-
- // Update row if state changed
- if (newState != -1) {
- values.put(CalendarAlerts.STATE, newState);
- state = newState;
-
- if (AlertUtils.BYPASS_DB) {
- AlertUtils.setAlertFiredInSharedPrefs(context, eventId, beginTime,
- alarmTime);
- }
- }
-
- if (state == CalendarAlerts.STATE_FIRED) {
- // Record the time posting to notification manager.
- // This is used for debugging missed alarms.
- values.put(CalendarAlerts.NOTIFY_TIME, currentTime);
- }
-
- // Write row to if anything changed
- if (values.size() > 0) cr.update(alertUri, values, null, null);
-
- if (state != CalendarAlerts.STATE_FIRED) {
- continue;
- }
-
- // TODO: Prefer accepted events in case of ties.
- NotificationInfo newInfo = new NotificationInfo(eventName, location,
- description, beginTime, endTime, eventId, allDay, newAlert);
-
- // Adjust for all day events to ensure the right bucket. Don't use the 1/4 event
- // duration grace period for these.
- long beginTimeAdjustedForAllDay = beginTime;
- String tz = null;
- if (allDay) {
- tz = TimeZone.getDefault().getID();
- beginTimeAdjustedForAllDay = Utils.convertAlldayUtcToLocal(null, beginTime,
- tz);
- }
-
- // Handle multiple alerts for the same event ID.
- if (eventIds.containsKey(eventId)) {
- NotificationInfo oldInfo = eventIds.get(eventId);
- long oldBeginTimeAdjustedForAllDay = oldInfo.startMillis;
- if (allDay) {
- oldBeginTimeAdjustedForAllDay = Utils.convertAlldayUtcToLocal(null,
- oldInfo.startMillis, tz);
- }
-
- // Determine whether to replace the previous reminder with this one.
- // Query results are sorted so this one will always have a lower start time.
- long oldStartInterval = oldBeginTimeAdjustedForAllDay - currentTime;
- long newStartInterval = beginTimeAdjustedForAllDay - currentTime;
- boolean dropOld;
- if (newStartInterval < 0 && oldStartInterval > 0) {
- // Use this reminder if this event started recently
- dropOld = Math.abs(newStartInterval) < MIN_DEPRIORITIZE_GRACE_PERIOD_MS;
- } else {
- // ... or if this one has a closer start time.
- dropOld = Math.abs(newStartInterval) < Math.abs(oldStartInterval);
- }
-
- if (dropOld) {
- // This is a recurring event that has a more relevant start time,
- // drop other reminder in favor of this one.
- //
- // It will only be present in 1 of these buckets; just remove from
- // multiple buckets since this occurrence is rare enough that the
- // inefficiency of multiple removals shouldn't be a big deal to
- // justify a more complicated data structure. Expired events don't
- // have individual notifications so we don't need to clean that up.
- highPriorityEvents.remove(oldInfo);
- mediumPriorityEvents.remove(oldInfo);
- if (DEBUG) {
- Log.d(TAG, "Dropping alert for recurring event ID:" + oldInfo.eventId
- + ", startTime:" + oldInfo.startMillis
- + " in favor of startTime:" + newInfo.startMillis);
- }
- } else {
- // Skip duplicate reminders for the same event instance.
- continue;
- }
- }
-
- // TODO: Prioritize by "primary" calendar
- eventIds.put(eventId, newInfo);
- long highPriorityCutoff = currentTime -
- getGracePeriodMs(beginTime, endTime, allDay);
-
- if (beginTimeAdjustedForAllDay > highPriorityCutoff) {
- // High priority = future events or events that just started
- highPriorityEvents.add(newInfo);
- } else if (allDay && tz != null && DateUtils.isToday(beginTimeAdjustedForAllDay)) {
- // Medium priority = in progress all day events
- mediumPriorityEvents.add(newInfo);
- } else {
- lowPriorityEvents.add(newInfo);
- }
- }
- // TODO(psliwowski): move this to account synchronization
- GlobalDismissManager.processEventIds(context, eventIds.keySet());
- } finally {
- if (alertCursor != null) {
- alertCursor.close();
- }
- }
- return numFired;
- }
-
- /**
- * High priority cutoff should be 1/4 event duration or 15 min, whichever is longer.
- */
- private static long getGracePeriodMs(long beginTime, long endTime, boolean allDay) {
- if (allDay) {
- // We don't want all day events to be high priority for hours, so automatically
- // demote these after 15 min.
- return MIN_DEPRIORITIZE_GRACE_PERIOD_MS;
- } else {
- return Math.max(MIN_DEPRIORITIZE_GRACE_PERIOD_MS, ((endTime - beginTime) / 4));
- }
- }
-
- private static String getDigestTitle(ArrayList<NotificationInfo> events) {
- StringBuilder digestTitle = new StringBuilder();
- for (NotificationInfo eventInfo : events) {
- if (!TextUtils.isEmpty(eventInfo.eventName)) {
- if (digestTitle.length() > 0) {
- digestTitle.append(", ");
- }
- digestTitle.append(eventInfo.eventName);
- }
- }
- return digestTitle.toString();
- }
-
- private static void postNotification(NotificationInfo info, String summaryText,
- Context context, boolean highPriority, NotificationPrefs prefs,
- NotificationMgr notificationMgr, int notificationId) {
- int priorityVal = Notification.PRIORITY_DEFAULT;
- if (highPriority) {
- priorityVal = Notification.PRIORITY_HIGH;
- }
-
- String tickerText = getTickerText(info.eventName, info.location);
- NotificationWrapper notification = AlertReceiver.makeExpandingNotification(context,
- info.eventName, summaryText, info.description, info.startMillis,
- info.endMillis, info.eventId, notificationId, prefs.getDoPopup(), priorityVal);
-
- boolean quietUpdate = true;
- String ringtone = NotificationPrefs.EMPTY_RINGTONE;
- if (info.newAlert) {
- quietUpdate = prefs.quietUpdate;
-
- // If we've already played a ringtone, don't play any more sounds so only
- // 1 sound per group of notifications.
- ringtone = prefs.getRingtoneAndSilence();
- }
- addNotificationOptions(notification, quietUpdate, tickerText,
- prefs.getDefaultVibrate(), ringtone,
- true); /* Show the LED for these non-expired events */
-
- // Post the notification.
- notificationMgr.notify(notificationId, notification);
-
- if (DEBUG) {
- Log.d(TAG, "Posting individual alarm notification, eventId:" + info.eventId
- + ", notificationId:" + notificationId
- + (TextUtils.isEmpty(ringtone) ? ", quiet" : ", LOUD")
- + (highPriority ? ", high-priority" : ""));
- }
- }
-
- private static String getTickerText(String eventName, String location) {
- String tickerText = eventName;
- if (!TextUtils.isEmpty(location)) {
- tickerText = eventName + " - " + location;
- }
- return tickerText;
- }
-
static class NotificationInfo {
String eventName;
String location;
@@ -927,196 +181,12 @@ public class AlertService extends Service {
}
}
- private static void addNotificationOptions(NotificationWrapper nw, boolean quietUpdate,
- String tickerText, boolean defaultVibrate, String reminderRingtone,
- boolean showLights) {
- Notification notification = nw.mNotification;
- if (showLights) {
- notification.flags |= Notification.FLAG_SHOW_LIGHTS;
- notification.defaults |= Notification.DEFAULT_LIGHTS;
- }
-
- // Quietly update notification bar. Nothing new. Maybe something just got deleted.
- if (!quietUpdate) {
- // Flash ticker in status bar
- if (!TextUtils.isEmpty(tickerText)) {
- notification.tickerText = tickerText;
- }
-
- // Generate either a pop-up dialog, status bar notification, or
- // neither. Pop-up dialog and status bar notification may include a
- // sound, an alert, or both. A status bar notification also includes
- // a toast.
- if (defaultVibrate) {
- notification.defaults |= Notification.DEFAULT_VIBRATE;
- }
-
- // Possibly generate a sound. If 'Silent' is chosen, the ringtone
- // string will be empty.
- notification.sound = TextUtils.isEmpty(reminderRingtone) ? null : Uri
- .parse(reminderRingtone);
- }
- }
-
- /* package */ static class NotificationPrefs {
- boolean quietUpdate;
- private Context context;
- private SharedPreferences prefs;
-
- // These are lazily initialized, do not access any of the following directly; use getters.
- private int doPopup = -1;
- private int defaultVibrate = -1;
- private String ringtone = null;
-
- private static final String EMPTY_RINGTONE = "";
-
- NotificationPrefs(Context context, SharedPreferences prefs, boolean quietUpdate) {
- this.context = context;
- this.prefs = prefs;
- this.quietUpdate = quietUpdate;
- }
-
- private boolean getDoPopup() {
- if (doPopup < 0) {
- if (prefs.getBoolean(GeneralPreferences.KEY_ALERTS_POPUP, false)) {
- doPopup = 1;
- } else {
- doPopup = 0;
- }
- }
- return doPopup == 1;
- }
-
- private boolean getDefaultVibrate() {
- if (defaultVibrate < 0) {
- defaultVibrate = Utils.getDefaultVibrate(context, prefs) ? 1 : 0;
- }
- return defaultVibrate == 1;
- }
-
- private String getRingtoneAndSilence() {
- if (ringtone == null) {
- if (quietUpdate) {
- ringtone = EMPTY_RINGTONE;
- } else {
- ringtone = Utils.getRingTonePreference(context);
- }
- }
- String retVal = ringtone;
- ringtone = EMPTY_RINGTONE;
- return retVal;
- }
- }
-
- private void doTimeChanged() {
- ContentResolver cr = getContentResolver();
- // TODO Move this into Provider
- rescheduleMissedAlarms(cr, this, AlertUtils.createAlarmManager(this));
- updateAlertNotification(this);
- }
-
- private static final String SORT_ORDER_ALARMTIME_ASC =
- CalendarContract.CalendarAlerts.ALARM_TIME + " ASC";
-
- private static final String WHERE_RESCHEDULE_MISSED_ALARMS =
- CalendarContract.CalendarAlerts.STATE
- + "="
- + CalendarContract.CalendarAlerts.STATE_SCHEDULED
- + " AND "
- + CalendarContract.CalendarAlerts.ALARM_TIME
- + "<?"
- + " AND "
- + CalendarContract.CalendarAlerts.ALARM_TIME
- + ">?"
- + " AND "
- + CalendarContract.CalendarAlerts.END + ">=?";
-
- /**
- * Searches the CalendarAlerts table for alarms that should have fired but
- * have not and then reschedules them. This method can be called at boot
- * time to restore alarms that may have been lost due to a phone reboot.
- *
- * @param cr the ContentResolver
- * @param context the Context
- * @param manager the AlarmManager
- */
- private static final void rescheduleMissedAlarms(ContentResolver cr, Context context,
- AlarmManagerInterface manager) {
- // Get all the alerts that have been scheduled but have not fired
- // and should have fired by now and are not too old.
- long now = System.currentTimeMillis();
- long ancient = now - DateUtils.DAY_IN_MILLIS;
- String[] projection = new String[] {
- CalendarContract.CalendarAlerts.ALARM_TIME,
- };
-
- // TODO: construct an explicit SQL query so that we can add
- // "GROUPBY" instead of doing a sort and de-dup
- Cursor cursor = cr.query(CalendarAlerts.CONTENT_URI, projection,
- WHERE_RESCHEDULE_MISSED_ALARMS, (new String[] {
- Long.toString(now), Long.toString(ancient), Long.toString(now)
- }), SORT_ORDER_ALARMTIME_ASC);
- if (cursor == null) {
- return;
- }
-
- if (DEBUG) {
- Log.d(TAG, "missed alarms found: " + cursor.getCount());
- }
-
- try {
- long alarmTime = -1;
-
- while (cursor.moveToNext()) {
- long newAlarmTime = cursor.getLong(0);
- if (alarmTime != newAlarmTime) {
- if (DEBUG) {
- Log.w(TAG, "rescheduling missed alarm. alarmTime: " + newAlarmTime);
- }
- AlertUtils.scheduleAlarm(context, manager, newAlarmTime);
- alarmTime = newAlarmTime;
- }
- }
- } finally {
- cursor.close();
- }
- }
-
- private final class ServiceHandler extends Handler {
- public ServiceHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- processMessage(msg);
- // NOTE: We MUST not call stopSelf() directly, since we need to
- // make sure the wake lock acquired by AlertReceiver is released.
- AlertReceiver.finishStartingService(AlertService.this, msg.arg1);
- }
- }
-
@Override
public void onCreate() {
- HandlerThread thread = new HandlerThread("AlertService",
- Process.THREAD_PRIORITY_BACKGROUND);
- thread.start();
-
- mServiceLooper = thread.getLooper();
- mServiceHandler = new ServiceHandler(mServiceLooper);
-
- // Flushes old fired alerts from internal storage, if needed.
- AlertUtils.flushOldAlertsFromInternalStorage(getApplication());
}
@Override
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;
}
diff --git a/src/com/android/calendar/alerts/AlertUtils.java b/src/com/android/calendar/alerts/AlertUtils.java
index fec7b111..b9aaec29 100644
--- a/src/com/android/calendar/alerts/AlertUtils.java
+++ b/src/com/android/calendar/alerts/AlertUtils.java
@@ -62,23 +62,6 @@ public class AlertUtils {
// alerts from other apps.
static boolean BYPASS_DB = true;
- // SharedPrefs table name for storing fired alerts. This prevents other installed
- // Calendar apps from eating the alerts.
- private static final String ALERTS_SHARED_PREFS_NAME = "calendar_alerts";
-
- // Keyname prefix for the alerts data in SharedPrefs. The key will contain a combo
- // of event ID, begin time, and alarm time. The value will be the fired time.
- private static final String KEY_FIRED_ALERT_PREFIX = "preference_alert_";
-
- // The last time the SharedPrefs was scanned and flushed of old alerts data.
- private static final String KEY_LAST_FLUSH_TIME_MS = "preference_flushTimeMs";
-
- // The # of days to save alert states in the shared prefs table, before flushing. This
- // can be any value, since AlertService will also check for a recent alertTime before
- // ringing the alert.
- private static final int FLUSH_INTERVAL_DAYS = 1;
- private static final int FLUSH_INTERVAL_MS = FLUSH_INTERVAL_DAYS * 24 * 60 * 60 * 1000;
-
/**
* Creates an AlarmManagerInterface that wraps a real AlarmManager. The alarm code
* was abstracted to an interface to make it testable.
@@ -110,109 +93,6 @@ public class AlertUtils {
*/
public static void scheduleAlarm(Context context, AlarmManagerInterface manager,
long alarmTime) {
- scheduleAlarmHelper(context, manager, alarmTime, false);
- }
-
- /**
- * Schedules the next alarm to silently refresh the notifications. Note that if there
- * is a pending silent refresh alarm, it will be replaced with this one.
- */
- static void scheduleNextNotificationRefresh(Context context, AlarmManagerInterface manager,
- long alarmTime) {
- scheduleAlarmHelper(context, manager, alarmTime, true);
- }
-
- private static void scheduleAlarmHelper(Context context, AlarmManagerInterface manager,
- long alarmTime, boolean quietUpdate) {
- int alarmType = AlarmManager.RTC_WAKEUP;
- Intent intent = new Intent(AlertReceiver.EVENT_REMINDER_APP_ACTION);
- intent.setClass(context, AlertReceiver.class);
- if (quietUpdate) {
- alarmType = AlarmManager.RTC;
- } else {
- // Set data field so we get a unique PendingIntent instance per alarm or else alarms
- // may be dropped.
- Uri.Builder builder = CalendarAlerts.CONTENT_URI.buildUpon();
- ContentUris.appendId(builder, alarmTime);
- intent.setData(builder.build());
- }
-
- intent.putExtra(CalendarContract.CalendarAlerts.ALARM_TIME, alarmTime);
- PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
- manager.set(alarmType, alarmTime, pi);
- }
-
- /**
- * Format the second line which shows time and location for single alert or the
- * number of events for multiple alerts
- * 1) Show time only for non-all day events
- * 2) No date for today
- * 3) Show "tomorrow" for tomorrow
- * 4) Show date for days beyond that
- */
- static String formatTimeLocation(Context context, long startMillis, boolean allDay,
- String location) {
- String tz = Utils.getTimeZone(context, null);
- Time time = new Time(tz);
- time.setToNow();
- int today = Time.getJulianDay(time.toMillis(false), time.gmtoff);
- time.set(startMillis);
- int eventDay = Time.getJulianDay(time.toMillis(false), allDay ? 0 : time.gmtoff);
-
- int flags = DateUtils.FORMAT_ABBREV_ALL;
- if (!allDay) {
- flags |= DateUtils.FORMAT_SHOW_TIME;
- if (DateFormat.is24HourFormat(context)) {
- flags |= DateUtils.FORMAT_24HOUR;
- }
- } else {
- flags |= DateUtils.FORMAT_UTC;
- }
-
- if (eventDay < today || eventDay > today + 1) {
- flags |= DateUtils.FORMAT_SHOW_DATE;
- }
-
- StringBuilder sb = new StringBuilder(Utils.formatDateRange(context, startMillis,
- startMillis, flags));
-
- if (!allDay && tz != Time.getCurrentTimezone()) {
- // Assumes time was set to the current tz
- time.set(startMillis);
- boolean isDST = time.isDst != 0;
- sb.append(" ").append(TimeZone.getTimeZone(tz).getDisplayName(
- isDST, TimeZone.SHORT, Locale.getDefault()));
- }
-
- if (eventDay == today + 1) {
- // Tomorrow
- sb.append(", ");
- sb.append(context.getString(R.string.tomorrow));
- }
-
- String loc;
- if (location != null && !TextUtils.isEmpty(loc = location.trim())) {
- sb.append(", ");
- sb.append(loc);
- }
- return sb.toString();
- }
-
- public static ContentValues makeContentValues(long eventId, long begin, long end,
- long alarmTime, int minutes) {
- ContentValues values = new ContentValues();
- values.put(CalendarAlerts.EVENT_ID, eventId);
- values.put(CalendarAlerts.BEGIN, begin);
- values.put(CalendarAlerts.END, end);
- values.put(CalendarAlerts.ALARM_TIME, alarmTime);
- long currentTime = System.currentTimeMillis();
- values.put(CalendarAlerts.CREATION_TIME, currentTime);
- values.put(CalendarAlerts.RECEIVED_TIME, 0);
- values.put(CalendarAlerts.NOTIFY_TIME, 0);
- values.put(CalendarAlerts.STATE, CalendarAlerts.STATE_SCHEDULED);
- values.put(CalendarAlerts.MINUTES, minutes);
- return values;
}
public static Intent buildEventViewIntent(Context c, long eventId, long begin, long end) {
@@ -225,103 +105,4 @@ public class AlertUtils {
i.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, end);
return i;
}
-
- public static SharedPreferences getFiredAlertsTable(Context context) {
- return context.getSharedPreferences(ALERTS_SHARED_PREFS_NAME, Context.MODE_PRIVATE);
- }
-
- private static String getFiredAlertsKey(long eventId, long beginTime,
- long alarmTime) {
- StringBuilder sb = new StringBuilder(KEY_FIRED_ALERT_PREFIX);
- sb.append(eventId);
- sb.append("_");
- sb.append(beginTime);
- sb.append("_");
- sb.append(alarmTime);
- return sb.toString();
- }
-
- /**
- * Returns whether the SharedPrefs storage indicates we have fired the alert before.
- */
- static boolean hasAlertFiredInSharedPrefs(Context context, long eventId, long beginTime,
- long alarmTime) {
- SharedPreferences prefs = getFiredAlertsTable(context);
- return prefs.contains(getFiredAlertsKey(eventId, beginTime, alarmTime));
- }
-
- /**
- * Store fired alert info in the SharedPrefs.
- */
- static void setAlertFiredInSharedPrefs(Context context, long eventId, long beginTime,
- long alarmTime) {
- // Store alarm time as the value too so we don't have to parse all the keys to flush
- // old alarms out of the table later.
- SharedPreferences prefs = getFiredAlertsTable(context);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putLong(getFiredAlertsKey(eventId, beginTime, alarmTime), alarmTime);
- editor.apply();
- }
-
- /**
- * Scans and flushes the internal storage of old alerts. Looks up the previous flush
- * time in SharedPrefs, and performs the flush if overdue. Otherwise, no-op.
- */
- static void flushOldAlertsFromInternalStorage(Context context) {
- if (BYPASS_DB) {
- SharedPreferences prefs = getFiredAlertsTable(context);
-
- // Only flush if it hasn't been done in a while.
- long nowTime = System.currentTimeMillis();
- long lastFlushTimeMs = prefs.getLong(KEY_LAST_FLUSH_TIME_MS, 0);
- if (nowTime - lastFlushTimeMs > FLUSH_INTERVAL_MS) {
- if (DEBUG) {
- Log.d(TAG, "Flushing old alerts from shared prefs table");
- }
-
- // Scan through all fired alert entries, removing old ones.
- SharedPreferences.Editor editor = prefs.edit();
- Time timeObj = new Time();
- for (Map.Entry<String, ?> entry : prefs.getAll().entrySet()) {
- String key = entry.getKey();
- Object value = entry.getValue();
- if (key.startsWith(KEY_FIRED_ALERT_PREFIX)) {
- long alertTime;
- if (value instanceof Long) {
- alertTime = (Long) value;
- } else {
- // Should never occur.
- Log.e(TAG,"SharedPrefs key " + key + " did not have Long value: " +
- value);
- continue;
- }
-
- if (nowTime - alertTime >= FLUSH_INTERVAL_MS) {
- editor.remove(key);
- if (DEBUG) {
- int ageInDays = getIntervalInDays(alertTime, nowTime, timeObj);
- Log.d(TAG, "SharedPrefs key " + key + ": removed (" + ageInDays +
- " days old)");
- }
- } else {
- if (DEBUG) {
- int ageInDays = getIntervalInDays(alertTime, nowTime, timeObj);
- Log.d(TAG, "SharedPrefs key " + key + ": keep (" + ageInDays +
- " days old)");
- }
- }
- }
- }
- editor.putLong(KEY_LAST_FLUSH_TIME_MS, nowTime);
- editor.apply();
- }
- }
- }
-
- private static int getIntervalInDays(long startMillis, long endMillis, Time timeObj) {
- timeObj.set(startMillis);
- int startDay = Time.getJulianDay(startMillis, timeObj.gmtoff);
- timeObj.set(endMillis);
- return Time.getJulianDay(endMillis, timeObj.gmtoff) - startDay;
- }
}
diff --git a/src/com/android/calendar/alerts/GlobalDismissManager.java b/src/com/android/calendar/alerts/GlobalDismissManager.java
index ce3402ca..27b3e162 100644
--- a/src/com/android/calendar/alerts/GlobalDismissManager.java
+++ b/src/com/android/calendar/alerts/GlobalDismissManager.java
@@ -32,8 +32,6 @@ import android.provider.CalendarContract.Events;
import android.util.Log;
import android.util.Pair;
-import com.android.calendar.CloudNotificationBackplane;
-import com.android.calendar.ExtensionsFactory;
import com.android.calendar.R;
import java.io.IOException;
@@ -49,113 +47,6 @@ import java.util.Set;
* Utilities for managing notification dismissal across devices.
*/
public class GlobalDismissManager extends BroadcastReceiver {
- private static class GlobalDismissId {
- public final String mAccountName;
- public final String mSyncId;
- public final long mStartTime;
-
- private GlobalDismissId(String accountName, String syncId, long startTime) {
- // TODO(psliwowski): Add guava library to use Preconditions class
- if (accountName == null) {
- throw new IllegalArgumentException("Account Name can not be set to null");
- } else if (syncId == null) {
- throw new IllegalArgumentException("SyncId can not be set to null");
- }
- mAccountName = accountName;
- mSyncId = syncId;
- mStartTime = startTime;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- GlobalDismissId that = (GlobalDismissId) o;
-
- if (mStartTime != that.mStartTime) {
- return false;
- }
- if (!mAccountName.equals(that.mAccountName)) {
- return false;
- }
- if (!mSyncId.equals(that.mSyncId)) {
- return false;
- }
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = mAccountName.hashCode();
- result = 31 * result + mSyncId.hashCode();
- result = 31 * result + (int) (mStartTime ^ (mStartTime >>> 32));
- return result;
- }
- }
-
- public static class LocalDismissId {
- public final String mAccountType;
- public final String mAccountName;
- public final long mEventId;
- public final long mStartTime;
-
- public LocalDismissId(String accountType, String accountName, long eventId,
- long startTime) {
- if (accountType == null) {
- throw new IllegalArgumentException("Account Type can not be null");
- } else if (accountName == null) {
- throw new IllegalArgumentException("Account Name can not be null");
- }
-
- mAccountType = accountType;
- mAccountName = accountName;
- mEventId = eventId;
- mStartTime = startTime;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- LocalDismissId that = (LocalDismissId) o;
-
- if (mEventId != that.mEventId) {
- return false;
- }
- if (mStartTime != that.mStartTime) {
- return false;
- }
- if (!mAccountName.equals(that.mAccountName)) {
- return false;
- }
- if (!mAccountType.equals(that.mAccountType)) {
- return false;
- }
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = mAccountType.hashCode();
- result = 31 * result + mAccountName.hashCode();
- result = 31 * result + (int) (mEventId ^ (mEventId >>> 32));
- result = 31 * result + (int) (mStartTime ^ (mStartTime >>> 32));
- return result;
- }
- }
-
public static class AlarmId {
public long mEventId;
public long mStart;
@@ -166,175 +57,6 @@ public class GlobalDismissManager extends BroadcastReceiver {
}
}
- private static final long TIME_TO_LIVE = 1 * 60 * 60 * 1000; // 1 hour
-
- private static final String TAG = "GlobalDismissManager";
- private static final String GOOGLE_ACCOUNT_TYPE = "com.google";
- private static final String GLOBAL_DISMISS_MANAGER_PREFS = "com.android.calendar.alerts.GDM";
- private static final String ACCOUNT_KEY = "known_accounts";
-
- static final String[] EVENT_PROJECTION = new String[] {
- Events._ID,
- Events.CALENDAR_ID
- };
- static final String[] EVENT_SYNC_PROJECTION = new String[] {
- Events._ID,
- Events._SYNC_ID
- };
- static final String[] CALENDARS_PROJECTION = new String[] {
- Calendars._ID,
- Calendars.ACCOUNT_NAME,
- Calendars.ACCOUNT_TYPE
- };
-
- public static final String KEY_PREFIX = "com.android.calendar.alerts.";
- public static final String SYNC_ID = KEY_PREFIX + "sync_id";
- public static final String START_TIME = KEY_PREFIX + "start_time";
- public static final String ACCOUNT_NAME = KEY_PREFIX + "account_name";
- public static final String DISMISS_INTENT = KEY_PREFIX + "DISMISS";
-
- // TODO(psliwowski): Look into persisting these like AlertUtils.ALERTS_SHARED_PREFS_NAME
- private static HashMap<GlobalDismissId, Long> sReceiverDismissCache =
- new HashMap<GlobalDismissId, Long>();
- private static HashMap<LocalDismissId, Long> sSenderDismissCache =
- new HashMap<LocalDismissId, Long>();
-
- /**
- * Look for unknown accounts in a set of events and associate with them.
- * Must not be called on main thread.
- *
- * @param context application context
- * @param eventIds IDs for events that have posted notifications that may be
- * dismissed.
- */
- public static void processEventIds(Context context, Set<Long> eventIds) {
- final String senderId = context.getResources().getString(R.string.notification_sender_id);
- if (senderId == null || senderId.isEmpty()) {
- Log.i(TAG, "no sender configured");
- return;
- }
- Map<Long, Long> eventsToCalendars = lookupEventToCalendarMap(context, eventIds);
- Set<Long> calendars = new LinkedHashSet<Long>();
- calendars.addAll(eventsToCalendars.values());
- if (calendars.isEmpty()) {
- Log.d(TAG, "found no calendars for events");
- return;
- }
-
- Map<Long, Pair<String, String>> calendarsToAccounts =
- lookupCalendarToAccountMap(context, calendars);
-
- if (calendarsToAccounts.isEmpty()) {
- Log.d(TAG, "found no accounts for calendars");
- return;
- }
-
- // filter out non-google accounts (necessary?)
- Set<String> accounts = new LinkedHashSet<String>();
- for (Pair<String, String> accountPair : calendarsToAccounts.values()) {
- if (GOOGLE_ACCOUNT_TYPE.equals(accountPair.first)) {
- accounts.add(accountPair.second);
- }
- }
-
- // filter out accounts we already know about
- SharedPreferences prefs =
- context.getSharedPreferences(GLOBAL_DISMISS_MANAGER_PREFS,
- Context.MODE_PRIVATE);
- Set<String> existingAccounts = prefs.getStringSet(ACCOUNT_KEY,
- new HashSet<String>());
- accounts.removeAll(existingAccounts);
-
- if (accounts.isEmpty()) {
- // nothing to do, we've already registered all the accounts.
- return;
- }
-
- // subscribe to remaining accounts
- CloudNotificationBackplane cnb =
- ExtensionsFactory.getCloudNotificationBackplane();
- if (cnb.open(context)) {
- for (String account : accounts) {
- try {
- if (cnb.subscribeToGroup(senderId, account, account)) {
- existingAccounts.add(account);
- }
- } catch (IOException e) {
- // Try again, next time the account triggers and alert.
- }
- }
- cnb.close();
- prefs.edit()
- .putStringSet(ACCOUNT_KEY, existingAccounts)
- .commit();
- }
- }
-
- /**
- * Some events don't have a global sync_id when they are dismissed. We need to wait
- * until the data provider is updated before we can send the global dismiss message.
- */
- public static void syncSenderDismissCache(Context context) {
- final String senderId = context.getResources().getString(R.string.notification_sender_id);
- if ("".equals(senderId)) {
- Log.i(TAG, "no sender configured");
- return;
- }
- CloudNotificationBackplane cnb = ExtensionsFactory.getCloudNotificationBackplane();
- if (!cnb.open(context)) {
- Log.i(TAG, "Unable to open cloud notification backplane");
-
- }
-
- long currentTime = System.currentTimeMillis();
- ContentResolver resolver = context.getContentResolver();
- synchronized (sSenderDismissCache) {
- Iterator<Map.Entry<LocalDismissId, Long>> it =
- sSenderDismissCache.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<LocalDismissId, Long> entry = it.next();
- LocalDismissId dismissId = entry.getKey();
-
- Uri uri = asSync(Events.CONTENT_URI, dismissId.mAccountType,
- dismissId.mAccountName);
- Cursor cursor = resolver.query(uri, EVENT_SYNC_PROJECTION,
- Events._ID + " = " + dismissId.mEventId, null, null);
- try {
- cursor.moveToPosition(-1);
- int sync_id_idx = cursor.getColumnIndex(Events._SYNC_ID);
- if (sync_id_idx != -1) {
- while (cursor.moveToNext()) {
- String syncId = cursor.getString(sync_id_idx);
- if (syncId != null) {
- Bundle data = new Bundle();
- long startTime = dismissId.mStartTime;
- String accountName = dismissId.mAccountName;
- data.putString(SYNC_ID, syncId);
- data.putString(START_TIME, Long.toString(startTime));
- data.putString(ACCOUNT_NAME, accountName);
- try {
- cnb.send(accountName, syncId + ":" + startTime, data);
- it.remove();
- } catch (IOException e) {
- // If we couldn't send, then leave dismissal in cache
- }
- }
- }
- }
- } finally {
- cursor.close();
- }
-
- // Remove old dismissals from cache after a certain time period
- if (currentTime - entry.getValue() > TIME_TO_LIVE) {
- it.remove();
- }
- }
- }
-
- cnb.close();
- }
-
/**
* Globally dismiss notifications that are backed by the same events.
*
@@ -347,178 +69,6 @@ public class GlobalDismissManager extends BroadcastReceiver {
for (AlarmId alarmId: alarmIds) {
eventIds.add(alarmId.mEventId);
}
- // find the mapping between calendars and events
- Map<Long, Long> eventsToCalendars = lookupEventToCalendarMap(context, eventIds);
- if (eventsToCalendars.isEmpty()) {
- Log.d(TAG, "found no calendars for events");
- return;
- }
-
- Set<Long> calendars = new LinkedHashSet<Long>();
- calendars.addAll(eventsToCalendars.values());
-
- // find the accounts associated with those calendars
- Map<Long, Pair<String, String>> calendarsToAccounts =
- lookupCalendarToAccountMap(context, calendars);
- if (calendarsToAccounts.isEmpty()) {
- Log.d(TAG, "found no accounts for calendars");
- return;
- }
-
- long currentTime = System.currentTimeMillis();
- for (AlarmId alarmId : alarmIds) {
- Long calendar = eventsToCalendars.get(alarmId.mEventId);
- Pair<String, String> account = calendarsToAccounts.get(calendar);
- if (GOOGLE_ACCOUNT_TYPE.equals(account.first)) {
- LocalDismissId dismissId = new LocalDismissId(account.first, account.second,
- alarmId.mEventId, alarmId.mStart);
- synchronized (sSenderDismissCache) {
- sSenderDismissCache.put(dismissId, currentTime);
- }
- }
- }
- syncSenderDismissCache(context);
- }
-
- private static Uri asSync(Uri uri, String accountType, String account) {
- return uri
- .buildUpon()
- .appendQueryParameter(
- android.provider.CalendarContract.CALLER_IS_SYNCADAPTER, "true")
- .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
- .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
- }
-
- /**
- * Build a selection over a set of row IDs
- *
- * @param ids row IDs to select
- * @param key row name for the table
- * @return a selection string suitable for a resolver query.
- */
- private static String buildMultipleIdQuery(Set<Long> ids, String key) {
- StringBuilder selection = new StringBuilder();
- boolean first = true;
- for (Long id : ids) {
- if (first) {
- first = false;
- } else {
- selection.append(" OR ");
- }
- selection.append(key);
- selection.append("=");
- selection.append(id);
- }
- return selection.toString();
- }
-
- /**
- * @param context application context
- * @param eventIds Event row IDs to query.
- * @return a map from event to calendar
- */
- private static Map<Long, Long> lookupEventToCalendarMap(Context context, Set<Long> eventIds) {
- Map<Long, Long> eventsToCalendars = new HashMap<Long, Long>();
- ContentResolver resolver = context.getContentResolver();
- String eventSelection = buildMultipleIdQuery(eventIds, Events._ID);
- Cursor eventCursor = resolver.query(Events.CONTENT_URI, EVENT_PROJECTION,
- eventSelection, null, null);
- try {
- eventCursor.moveToPosition(-1);
- int calendar_id_idx = eventCursor.getColumnIndex(Events.CALENDAR_ID);
- int event_id_idx = eventCursor.getColumnIndex(Events._ID);
- if (calendar_id_idx != -1 && event_id_idx != -1) {
- while (eventCursor.moveToNext()) {
- eventsToCalendars.put(eventCursor.getLong(event_id_idx),
- eventCursor.getLong(calendar_id_idx));
- }
- }
- } finally {
- eventCursor.close();
- }
- return eventsToCalendars;
- }
-
- /**
- * @param context application context
- * @param calendars Calendar row IDs to query.
- * @return a map from Calendar to a pair (account type, account name)
- */
- private static Map<Long, Pair<String, String>> lookupCalendarToAccountMap(Context context,
- Set<Long> calendars) {
- Map<Long, Pair<String, String>> calendarsToAccounts =
- new HashMap<Long, Pair<String, String>>();
- ContentResolver resolver = context.getContentResolver();
- String calendarSelection = buildMultipleIdQuery(calendars, Calendars._ID);
- Cursor calendarCursor = resolver.query(Calendars.CONTENT_URI, CALENDARS_PROJECTION,
- calendarSelection, null, null);
- try {
- calendarCursor.moveToPosition(-1);
- int calendar_id_idx = calendarCursor.getColumnIndex(Calendars._ID);
- int account_name_idx = calendarCursor.getColumnIndex(Calendars.ACCOUNT_NAME);
- int account_type_idx = calendarCursor.getColumnIndex(Calendars.ACCOUNT_TYPE);
- if (calendar_id_idx != -1 && account_name_idx != -1 && account_type_idx != -1) {
- while (calendarCursor.moveToNext()) {
- Long id = calendarCursor.getLong(calendar_id_idx);
- String name = calendarCursor.getString(account_name_idx);
- String type = calendarCursor.getString(account_type_idx);
- if (name != null && type != null) {
- calendarsToAccounts.put(id, new Pair<String, String>(type, name));
- }
- }
- }
- } finally {
- calendarCursor.close();
- }
- return calendarsToAccounts;
- }
-
- /**
- * We can get global dismisses for events we don't know exists yet, so sync our cache
- * with the data provider whenever it updates.
- */
- public static void syncReceiverDismissCache(Context context) {
- ContentResolver resolver = context.getContentResolver();
- long currentTime = System.currentTimeMillis();
- synchronized (sReceiverDismissCache) {
- Iterator<Map.Entry<GlobalDismissId, Long>> it =
- sReceiverDismissCache.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<GlobalDismissId, Long> entry = it.next();
- GlobalDismissId globalDismissId = entry.getKey();
- Uri uri = GlobalDismissManager.asSync(Events.CONTENT_URI,
- GlobalDismissManager.GOOGLE_ACCOUNT_TYPE, globalDismissId.mAccountName);
- Cursor cursor = resolver.query(uri, GlobalDismissManager.EVENT_SYNC_PROJECTION,
- Events._SYNC_ID + " = '" + globalDismissId.mSyncId + "'",
- null, null);
- try {
- int event_id_idx = cursor.getColumnIndex(Events._ID);
- cursor.moveToFirst();
- if (event_id_idx != -1 && !cursor.isAfterLast()) {
- long eventId = cursor.getLong(event_id_idx);
- ContentValues values = new ContentValues();
- String selection = "(" + CalendarAlerts.STATE + "=" +
- CalendarAlerts.STATE_FIRED + " OR " +
- CalendarAlerts.STATE + "=" +
- CalendarAlerts.STATE_SCHEDULED + ") AND " +
- CalendarAlerts.EVENT_ID + "=" + eventId + " AND " +
- CalendarAlerts.BEGIN + "=" + globalDismissId.mStartTime;
- values.put(CalendarAlerts.STATE, CalendarAlerts.STATE_DISMISSED);
- int rows = resolver.update(CalendarAlerts.CONTENT_URI, values,
- selection, null);
- if (rows > 0) {
- it.remove();
- }
- }
- } finally {
- cursor.close();
- }
-
- if (currentTime - entry.getValue() > TIME_TO_LIVE) {
- it.remove();
- }
- }
- }
}
@Override
@@ -527,19 +77,6 @@ public class GlobalDismissManager extends BroadcastReceiver {
new AsyncTask<Pair<Context, Intent>, Void, Void>() {
@Override
protected Void doInBackground(Pair<Context, Intent>... params) {
- Context context = params[0].first;
- Intent intent = params[0].second;
- if (intent.hasExtra(SYNC_ID) && intent.hasExtra(ACCOUNT_NAME)
- && intent.hasExtra(START_TIME)) {
- synchronized (sReceiverDismissCache) {
- sReceiverDismissCache.put(new GlobalDismissId(
- intent.getStringExtra(ACCOUNT_NAME),
- intent.getStringExtra(SYNC_ID),
- Long.parseLong(intent.getStringExtra(START_TIME))
- ), System.currentTimeMillis());
- }
- AlertService.updateAlertNotification(context);
- }
return null;
}
}.execute(new Pair<Context, Intent>(context, intent));
diff --git a/src/com/android/calendar/alerts/QuickResponseActivity.java b/src/com/android/calendar/alerts/QuickResponseActivity.java
index f7e08883..3d291d02 100644
--- a/src/com/android/calendar/alerts/QuickResponseActivity.java
+++ b/src/com/android/calendar/alerts/QuickResponseActivity.java
@@ -103,23 +103,6 @@ public class QuickResponseActivity extends ListActivity implements OnItemClickLi
@Override
public void run() {
- Intent emailIntent = AlertReceiver.createEmailIntent(QuickResponseActivity.this,
- mEventId, mBody);
- if (emailIntent != null) {
- try {
- startActivity(emailIntent);
- finish();
- } catch (ActivityNotFoundException ex) {
- QuickResponseActivity.this.getListView().post(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(QuickResponseActivity.this,
- R.string.quick_response_email_failed, Toast.LENGTH_LONG);
- finish();
- }
- });
- }
- }
}
}
}
diff --git a/src/com/android/calendar/alerts/SnoozeAlarmsService.java b/src/com/android/calendar/alerts/SnoozeAlarmsService.java
deleted file mode 100644
index 6ef983d5..00000000
--- a/src/com/android/calendar/alerts/SnoozeAlarmsService.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2012 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.alerts;
-
-import android.app.IntentService;
-import android.app.NotificationManager;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.IBinder;
-import android.provider.CalendarContract.CalendarAlerts;
-
-/**
- * Service for asynchronously marking a fired alarm as dismissed and scheduling
- * a new alarm in the future.
- */
-public class SnoozeAlarmsService extends IntentService {
- private static final String[] PROJECTION = new String[] {
- CalendarAlerts.STATE,
- };
- private static final int COLUMN_INDEX_STATE = 0;
-
- public SnoozeAlarmsService() {
- super("SnoozeAlarmsService");
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
- @Override
- public void onHandleIntent(Intent intent) {
-
- long eventId = intent.getLongExtra(AlertUtils.EVENT_ID_KEY, -1);
- long eventStart = intent.getLongExtra(AlertUtils.EVENT_START_KEY, -1);
- long eventEnd = intent.getLongExtra(AlertUtils.EVENT_END_KEY, -1);
-
- // The ID reserved for the expired notification digest should never be passed in
- // here, so use that as a default.
- int notificationId = intent.getIntExtra(AlertUtils.NOTIFICATION_ID_KEY,
- AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID);
-
- if (eventId != -1) {
- ContentResolver resolver = getContentResolver();
-
- // Remove notification
- if (notificationId != AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID) {
- NotificationManager nm =
- (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- nm.cancel(notificationId);
- }
-
- // Dismiss current alarm
- Uri uri = CalendarAlerts.CONTENT_URI;
- String selection = CalendarAlerts.STATE + "=" + CalendarAlerts.STATE_FIRED + " AND " +
- CalendarAlerts.EVENT_ID + "=" + eventId;
- ContentValues dismissValues = new ContentValues();
- dismissValues.put(PROJECTION[COLUMN_INDEX_STATE], CalendarAlerts.STATE_DISMISSED);
- resolver.update(uri, dismissValues, selection, null);
-
- // Add a new alarm
- long alarmTime = System.currentTimeMillis() + AlertUtils.SNOOZE_DELAY;
- ContentValues values = AlertUtils.makeContentValues(eventId, eventStart, eventEnd,
- alarmTime, 0);
- resolver.insert(uri, values);
- AlertUtils.scheduleAlarm(SnoozeAlarmsService.this, AlertUtils.createAlarmManager(this),
- alarmTime);
- }
- AlertService.updateAlertNotification(this);
- stopSelf();
- }
-}
diff --git a/src/com/android/calendar/event/AttendeesView.java b/src/com/android/calendar/event/AttendeesView.java
deleted file mode 100644
index a54d40b6..00000000
--- a/src/com/android/calendar/event/AttendeesView.java
+++ /dev/null
@@ -1,486 +0,0 @@
- /*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.calendar.event;
-
-import com.android.calendar.CalendarEventModel.Attendee;
-import com.android.calendar.ContactsAsyncHelper;
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-import com.android.calendar.event.EditEventHelper.AttendeeItem;
-import com.android.common.Rfc822Validator;
-
-import android.content.AsyncQueryHandler;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Paint;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.provider.CalendarContract.Attendees;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Identity;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
-import android.text.TextUtils;
-import android.text.util.Rfc822Token;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
-import android.widget.QuickContactBadge;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-
-public class AttendeesView extends LinearLayout implements View.OnClickListener {
- private static final String TAG = "AttendeesView";
- private static final boolean DEBUG = false;
-
- private static final int EMAIL_PROJECTION_CONTACT_ID_INDEX = 0;
- private static final int EMAIL_PROJECTION_CONTACT_LOOKUP_INDEX = 1;
- private static final int EMAIL_PROJECTION_PHOTO_ID_INDEX = 2;
-
- private static final String[] PROJECTION = new String[] {
- RawContacts.CONTACT_ID, // 0
- Contacts.LOOKUP_KEY, // 1
- Contacts.PHOTO_ID, // 2
- };
-
- private final Context mContext;
- private final LayoutInflater mInflater;
- private final PresenceQueryHandler mPresenceQueryHandler;
- private final Drawable mDefaultBadge;
- private final ColorMatrixColorFilter mGrayscaleFilter;
-
- // TextView shown at the top of each type of attendees
- // e.g.
- // Yes <-- divider
- // example_for_yes <exampleyes@example.com>
- // No <-- divider
- // example_for_no <exampleno@example.com>
- private final CharSequence[] mEntries;
- private final View mDividerForYes;
- private final View mDividerForNo;
- private final View mDividerForMaybe;
- private final View mDividerForNoResponse;
- private final int mNoResponsePhotoAlpha;
- private final int mDefaultPhotoAlpha;
- private Rfc822Validator mValidator;
-
- // Number of attendees responding or not responding.
- private int mYes;
- private int mNo;
- private int mMaybe;
- private int mNoResponse;
-
- // Cache for loaded photos
- HashMap<String, Drawable> mRecycledPhotos;
-
- public AttendeesView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mContext = context;
- mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mPresenceQueryHandler = new PresenceQueryHandler(context.getContentResolver());
-
- final Resources resources = context.getResources();
- mDefaultBadge = resources.getDrawable(R.drawable.ic_contact_picture);
- mNoResponsePhotoAlpha =
- resources.getInteger(R.integer.noresponse_attendee_photo_alpha_level);
- mDefaultPhotoAlpha = resources.getInteger(R.integer.default_attendee_photo_alpha_level);
-
- // Create dividers between groups of attendees (accepted, declined, etc...)
- mEntries = resources.getTextArray(R.array.response_labels1);
- mDividerForYes = constructDividerView(mEntries[1]);
- mDividerForNo = constructDividerView(mEntries[3]);
- mDividerForMaybe = constructDividerView(mEntries[2]);
- mDividerForNoResponse = constructDividerView(mEntries[0]);
-
- // Create a filter to convert photos of declined attendees to grayscale.
- ColorMatrix matrix = new ColorMatrix();
- matrix.setSaturation(0);
- mGrayscaleFilter = new ColorMatrixColorFilter(matrix);
-
- }
-
- // Disable/enable removal of attendings
- @Override
- public void setEnabled(boolean enabled) {
- super.setEnabled(enabled);
- int visibility = isEnabled() ? View.VISIBLE : View.GONE;
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- View minusButton = child.findViewById(R.id.contact_remove);
- if (minusButton != null) {
- minusButton.setVisibility(visibility);
- }
- }
- }
-
- public void setRfc822Validator(Rfc822Validator validator) {
- mValidator = validator;
- }
-
- private View constructDividerView(CharSequence label) {
- final TextView textView =
- (TextView)mInflater.inflate(R.layout.event_info_label, this, false);
- textView.setText(label);
- textView.setClickable(false);
- return textView;
- }
-
- // Add the number of attendees in the specific status (corresponding to the divider) in
- // parenthesis next to the label
- private void updateDividerViewLabel(View divider, CharSequence label, int count) {
- if (count <= 0) {
- ((TextView)divider).setText(label);
- }
- else {
- ((TextView)divider).setText(label + " (" + count + ")");
- }
- }
-
-
- /**
- * Inflates a layout for a given attendee view and set up each element in it, and returns
- * the constructed View object. The object is also stored in {@link AttendeeItem#mView}.
- */
- private View constructAttendeeView(AttendeeItem item) {
- item.mView = mInflater.inflate(R.layout.contact_item, null);
- return updateAttendeeView(item);
- }
-
- /**
- * Set up each element in {@link AttendeeItem#mView} using the latest information. View
- * object is reused.
- */
- private View updateAttendeeView(AttendeeItem item) {
- final Attendee attendee = item.mAttendee;
- final View view = item.mView;
- final TextView nameView = (TextView) view.findViewById(R.id.name);
- nameView.setText(TextUtils.isEmpty(attendee.mName) ? attendee.mEmail : attendee.mName);
- if (item.mRemoved) {
- nameView.setPaintFlags(Paint.STRIKE_THRU_TEXT_FLAG | nameView.getPaintFlags());
- } else {
- nameView.setPaintFlags((~Paint.STRIKE_THRU_TEXT_FLAG) & nameView.getPaintFlags());
- }
-
- // Set up the Image button even if the view is disabled
- // Everything will be ready when the view is enabled later
- final ImageButton button = (ImageButton) view.findViewById(R.id.contact_remove);
- button.setVisibility(isEnabled() ? View.VISIBLE : View.GONE);
- button.setTag(item);
- if (item.mRemoved) {
- button.setImageResource(R.drawable.ic_menu_add_field_holo_light);
- button.setContentDescription(mContext.getString(R.string.accessibility_add_attendee));
- } else {
- button.setImageResource(R.drawable.ic_menu_remove_field_holo_light);
- button.setContentDescription(mContext.
- getString(R.string.accessibility_remove_attendee));
- }
- button.setOnClickListener(this);
-
- final QuickContactBadge badgeView = (QuickContactBadge) view.findViewById(R.id.badge);
-
- Drawable badge = null;
- // Search for photo in recycled photos
- if (mRecycledPhotos != null) {
- badge = mRecycledPhotos.get(item.mAttendee.mEmail);
- }
- if (badge != null) {
- item.mBadge = badge;
- }
- badgeView.setImageDrawable(item.mBadge);
-
- if (item.mAttendee.mStatus == Attendees.ATTENDEE_STATUS_NONE) {
- item.mBadge.setAlpha(mNoResponsePhotoAlpha);
- } else {
- item.mBadge.setAlpha(mDefaultPhotoAlpha);
- }
- if (item.mAttendee.mStatus == Attendees.ATTENDEE_STATUS_DECLINED) {
- item.mBadge.setColorFilter(mGrayscaleFilter);
- } else {
- item.mBadge.setColorFilter(null);
- }
-
- // If we know the lookup-uri of the contact, it is a good idea to set this here. This
- // allows QuickContact to be started without an extra database lookup. If we don't know
- // the lookup uri (yet), we can set Email and QuickContact will lookup once tapped.
- if (item.mContactLookupUri != null) {
- badgeView.assignContactUri(item.mContactLookupUri);
- } else {
- badgeView.assignContactFromEmail(item.mAttendee.mEmail, true);
- }
- badgeView.setMaxHeight(60);
-
- return view;
- }
-
- public boolean contains(Attendee attendee) {
- final int size = getChildCount();
- for (int i = 0; i < size; i++) {
- final View view = getChildAt(i);
- if (view instanceof TextView) { // divider
- continue;
- }
- AttendeeItem attendeeItem = (AttendeeItem) view.getTag();
- if (TextUtils.equals(attendee.mEmail, attendeeItem.mAttendee.mEmail)) {
- return true;
- }
- }
- return false;
- }
-
- public void clearAttendees() {
-
- // Before clearing the views, save all the badges. The updateAtendeeView will use the saved
- // photo instead of the default badge thus prevent switching between the two while the
- // most current photo is loaded in the background.
- mRecycledPhotos = new HashMap<String, Drawable> ();
- final int size = getChildCount();
- for (int i = 0; i < size; i++) {
- final View view = getChildAt(i);
- if (view instanceof TextView) { // divider
- continue;
- }
- AttendeeItem attendeeItem = (AttendeeItem) view.getTag();
- mRecycledPhotos.put(attendeeItem.mAttendee.mEmail, attendeeItem.mBadge);
- }
-
- removeAllViews();
- mYes = 0;
- mNo = 0;
- mMaybe = 0;
- mNoResponse = 0;
- }
-
- private void addOneAttendee(Attendee attendee) {
- if (contains(attendee)) {
- return;
- }
- final AttendeeItem item = new AttendeeItem(attendee, mDefaultBadge);
- final int status = attendee.mStatus;
- final int index;
- boolean firstAttendeeInCategory = false;
- switch (status) {
- case Attendees.ATTENDEE_STATUS_ACCEPTED: {
- final int startIndex = 0;
- updateDividerViewLabel(mDividerForYes, mEntries[1], mYes + 1);
- if (mYes == 0) {
- addView(mDividerForYes, startIndex);
- firstAttendeeInCategory = true;
- }
- mYes++;
- index = startIndex + mYes;
- break;
- }
- case Attendees.ATTENDEE_STATUS_DECLINED: {
- final int startIndex = (mYes == 0 ? 0 : 1 + mYes);
- updateDividerViewLabel(mDividerForNo, mEntries[3], mNo + 1);
- if (mNo == 0) {
- addView(mDividerForNo, startIndex);
- firstAttendeeInCategory = true;
- }
- mNo++;
- index = startIndex + mNo;
- break;
- }
- case Attendees.ATTENDEE_STATUS_TENTATIVE: {
- final int startIndex = (mYes == 0 ? 0 : 1 + mYes) + (mNo == 0 ? 0 : 1 + mNo);
- updateDividerViewLabel(mDividerForMaybe, mEntries[2], mMaybe + 1);
- if (mMaybe == 0) {
- addView(mDividerForMaybe, startIndex);
- firstAttendeeInCategory = true;
- }
- mMaybe++;
- index = startIndex + mMaybe;
- break;
- }
- default: {
- final int startIndex = (mYes == 0 ? 0 : 1 + mYes) + (mNo == 0 ? 0 : 1 + mNo)
- + (mMaybe == 0 ? 0 : 1 + mMaybe);
- updateDividerViewLabel(mDividerForNoResponse, mEntries[0], mNoResponse + 1);
- if (mNoResponse == 0) {
- addView(mDividerForNoResponse, startIndex);
- firstAttendeeInCategory = true;
- }
- mNoResponse++;
- index = startIndex + mNoResponse;
- break;
- }
- }
-
- final View view = constructAttendeeView(item);
- view.setTag(item);
- addView(view, index);
- // Show separator between Attendees
- if (!firstAttendeeInCategory) {
- View prevItem = getChildAt(index - 1);
- if (prevItem != null) {
- View Separator = prevItem.findViewById(R.id.contact_separator);
- if (Separator != null) {
- Separator.setVisibility(View.VISIBLE);
- }
- }
- }
-
- Uri uri;
- String selection = null;
- String[] selectionArgs = null;
- if (attendee.mIdentity != null && attendee.mIdNamespace != null) {
- // Query by identity + namespace
- uri = Data.CONTENT_URI;
- selection = Data.MIMETYPE + "=? AND " + Identity.IDENTITY + "=? AND " +
- Identity.NAMESPACE + "=?";
- selectionArgs = new String[] {Identity.CONTENT_ITEM_TYPE, attendee.mIdentity,
- attendee.mIdNamespace};
- } else {
- // Query by email
- uri = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(attendee.mEmail));
- }
-
- mPresenceQueryHandler.startQuery(item.mUpdateCounts + 1, item, uri, PROJECTION, selection,
- selectionArgs, null);
- }
-
- public void addAttendees(ArrayList<Attendee> attendees) {
- synchronized (this) {
- for (final Attendee attendee : attendees) {
- addOneAttendee(attendee);
- }
- }
- }
-
- public void addAttendees(HashMap<String, Attendee> attendees) {
- synchronized (this) {
- for (final Attendee attendee : attendees.values()) {
- addOneAttendee(attendee);
- }
- }
- }
-
- public void addAttendees(String attendees) {
- final LinkedHashSet<Rfc822Token> addresses =
- EditEventHelper.getAddressesFromList(attendees, mValidator);
- synchronized (this) {
- for (final Rfc822Token address : addresses) {
- final Attendee attendee = new Attendee(address.getName(), address.getAddress());
- if (TextUtils.isEmpty(attendee.mName)) {
- attendee.mName = attendee.mEmail;
- }
- addOneAttendee(attendee);
- }
- }
- }
-
- /**
- * Returns true when the attendee at that index is marked as "removed" (the name of
- * the attendee is shown with a strike through line).
- */
- public boolean isMarkAsRemoved(int index) {
- final View view = getChildAt(index);
- if (view instanceof TextView) { // divider
- return false;
- }
- return ((AttendeeItem) view.getTag()).mRemoved;
- }
-
- // TODO put this into a Loader for auto-requeries
- private class PresenceQueryHandler extends AsyncQueryHandler {
- public PresenceQueryHandler(ContentResolver cr) {
- super(cr);
- }
-
- @Override
- protected void onQueryComplete(int queryIndex, Object cookie, Cursor cursor) {
- if (cursor == null || cookie == null) {
- if (DEBUG) {
- Log.d(TAG, "onQueryComplete: cursor=" + cursor + ", cookie=" + cookie);
- }
- return;
- }
-
- final AttendeeItem item = (AttendeeItem)cookie;
- try {
- if (item.mUpdateCounts < queryIndex) {
- item.mUpdateCounts = queryIndex;
- if (cursor.moveToFirst()) {
- final long contactId = cursor.getLong(EMAIL_PROJECTION_CONTACT_ID_INDEX);
- final Uri contactUri =
- ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
-
- final String lookupKey =
- cursor.getString(EMAIL_PROJECTION_CONTACT_LOOKUP_INDEX);
- item.mContactLookupUri = Contacts.getLookupUri(contactId, lookupKey);
-
- final long photoId = cursor.getLong(EMAIL_PROJECTION_PHOTO_ID_INDEX);
- // If we found a picture, start the async loading
- if (photoId > 0) {
- // Query for this contacts picture
- ContactsAsyncHelper.retrieveContactPhotoAsync(
- mContext, item, new Runnable() {
- @Override
- public void run() {
- updateAttendeeView(item);
- }
- }, contactUri);
- } else {
- // call update view to make sure that the lookup key gets set in
- // the QuickContactBadge
- updateAttendeeView(item);
- }
- } else {
- // Contact not found. For real emails, keep the QuickContactBadge with
- // its Email address set, so that the user can create a contact by tapping.
- item.mContactLookupUri = null;
- if (!Utils.isValidEmail(item.mAttendee.mEmail)) {
- item.mAttendee.mEmail = null;
- updateAttendeeView(item);
- }
- }
- }
- } finally {
- cursor.close();
- }
- }
- }
-
- public Attendee getItem(int index) {
- final View view = getChildAt(index);
- if (view instanceof TextView) { // divider
- return null;
- }
- return ((AttendeeItem) view.getTag()).mAttendee;
- }
-
- @Override
- public void onClick(View view) {
- // Button corresponding to R.id.contact_remove.
- final AttendeeItem item = (AttendeeItem) view.getTag();
- item.mRemoved = !item.mRemoved;
- updateAttendeeView(item);
- }
-}
diff --git a/src/com/android/calendar/event/CreateEventDialogFragment.java b/src/com/android/calendar/event/CreateEventDialogFragment.java
deleted file mode 100644
index 0381b302..00000000
--- a/src/com/android/calendar/event/CreateEventDialogFragment.java
+++ /dev/null
@@ -1,325 +0,0 @@
-/* Copyright (C) 2012 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.event;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.provider.CalendarContract;
-import android.provider.CalendarContract.Calendars;
-import android.provider.Settings;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.android.calendar.AsyncQueryService;
-import com.android.calendar.CalendarController;
-import com.android.calendar.CalendarController.EventType;
-import com.android.calendar.CalendarEventModel;
-import com.android.calendar.GeneralPreferences;
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-
-
-/**
- * Allows the user to quickly create a new all-day event from the calendar's month view.
- */
-public class CreateEventDialogFragment extends DialogFragment implements TextWatcher {
-
- private static final String TAG = "CreateEventDialogFragment";
-
- private static final int TOKEN_CALENDARS = 1 << 3;
-
- private static final String KEY_DATE_STRING = "date_string";
- private static final String KEY_DATE_IN_MILLIS = "date_in_millis";
- private static final String EVENT_DATE_FORMAT = "%a, %b %d, %Y";
-
- private AlertDialog mAlertDialog;
-
- private CalendarQueryService mService;
-
- private EditText mEventTitle;
- private View mColor;
-
- private TextView mCalendarName;
- private TextView mAccountName;
- private TextView mDate;
- private Button mButtonAddEvent;
-
- private CalendarController mController;
- private EditEventHelper mEditEventHelper;
-
- private String mDateString;
- private long mDateInMillis;
-
- private CalendarEventModel mModel;
- private long mCalendarId = -1;
- private String mCalendarOwner;
-
- private class CalendarQueryService extends AsyncQueryService {
-
- /**
- * @param context
- */
- public CalendarQueryService(Context context) {
- super(context);
- }
-
- @Override
- public void onQueryComplete(int token, Object cookie, Cursor cursor) {
- setDefaultCalendarView(cursor);
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- public CreateEventDialogFragment() {
- // Empty constructor required for DialogFragment.
- }
-
- public CreateEventDialogFragment(Time day) {
- setDay(day);
- }
-
- public void setDay(Time day) {
- mDateString = day.format(EVENT_DATE_FORMAT);
- mDateInMillis = day.toMillis(true);
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (savedInstanceState != null) {
- mDateString = savedInstanceState.getString(KEY_DATE_STRING);
- mDateInMillis = savedInstanceState.getLong(KEY_DATE_IN_MILLIS);
- }
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- final Activity activity = getActivity();
- final LayoutInflater layoutInflater = (LayoutInflater) activity
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- View view = layoutInflater.inflate(R.layout.create_event_dialog, null);
-
- mColor = view.findViewById(R.id.color);
- mCalendarName = (TextView) view.findViewById(R.id.calendar_name);
- mAccountName = (TextView) view.findViewById(R.id.account_name);
-
- mEventTitle = (EditText) view.findViewById(R.id.event_title);
- mEventTitle.addTextChangedListener(this);
-
- mDate = (TextView) view.findViewById(R.id.event_day);
- if (mDateString != null) {
- mDate.setText(mDateString);
- }
-
- mAlertDialog = new AlertDialog.Builder(activity)
- .setTitle(R.string.new_event_dialog_label)
- .setView(view)
- .setPositiveButton(R.string.create_event_dialog_save,
- new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- createAllDayEvent();
- dismiss();
- }
- })
- .setNeutralButton(R.string.edit_label,
- new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- mController.sendEventRelatedEventWithExtraWithTitleWithCalendarId(this,
- EventType.CREATE_EVENT, -1, mDateInMillis,
- mDateInMillis + DateUtils.DAY_IN_MILLIS, 0, 0,
- CalendarController.EXTRA_CREATE_ALL_DAY, -1,
- mEventTitle.getText().toString(),
- mCalendarId);
- dismiss();
- }
- })
- .setNegativeButton(android.R.string.cancel, null)
- .create();
-
- return mAlertDialog;
- }
-
- @Override
- public void onResume() {
- super.onResume();
- if (mButtonAddEvent == null) {
- mButtonAddEvent = mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
- mButtonAddEvent.setEnabled(mEventTitle.getText().toString().length() > 0);
- }
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putString(KEY_DATE_STRING, mDateString);
- outState.putLong(KEY_DATE_IN_MILLIS, mDateInMillis);
- }
-
- @Override
- public void onActivityCreated(Bundle args) {
- super.onActivityCreated(args);
- final Context context = getActivity();
- mController = CalendarController.getInstance(getActivity());
- mEditEventHelper = new EditEventHelper(context);
- mModel = new CalendarEventModel(context);
- mService = new CalendarQueryService(context);
- mService.startQuery(TOKEN_CALENDARS, null, Calendars.CONTENT_URI,
- EditEventHelper.CALENDARS_PROJECTION,
- EditEventHelper.CALENDARS_WHERE_WRITEABLE_VISIBLE, null,
- null);
- }
-
- private void createAllDayEvent() {
- mModel.mStart = mDateInMillis;
- mModel.mEnd = mDateInMillis + DateUtils.DAY_IN_MILLIS;
- mModel.mTitle = mEventTitle.getText().toString();
- mModel.mAllDay = true;
- mModel.mCalendarId = mCalendarId;
- mModel.mOwnerAccount = mCalendarOwner;
-
- if (mEditEventHelper.saveEvent(mModel, null, 0)) {
- Toast.makeText(getActivity(), R.string.creating_event, Toast.LENGTH_SHORT).show();
- }
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- // Do nothing.
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- // Do nothing.
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- if (mButtonAddEvent != null) {
- mButtonAddEvent.setEnabled(s.length() > 0);
- }
- }
-
- // Find the calendar position in the cursor that matches calendar in
- // preference
- private void setDefaultCalendarView(Cursor cursor) {
- if (cursor == null || cursor.getCount() == 0) {
- // Create an error message for the user that, when clicked,
- // will exit this activity without saving the event.
- dismiss();
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- builder.setTitle(R.string.no_syncable_calendars).setIconAttribute(
- android.R.attr.alertDialogIcon).setMessage(R.string.no_calendars_found)
- .setPositiveButton(R.string.add_account, new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- final Activity activity = getActivity();
- if (activity != null) {
- Intent nextIntent = new Intent(Settings.ACTION_ADD_ACCOUNT);
- final String[] array = {"com.android.calendar"};
- nextIntent.putExtra(Settings.EXTRA_AUTHORITIES, array);
- nextIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
- Intent.FLAG_ACTIVITY_NEW_TASK);
- activity.startActivity(nextIntent);
- }
- }
- })
- .setNegativeButton(android.R.string.no, null);
- builder.show();
- return;
- }
-
-
- String defaultCalendar = null;
- final Activity activity = getActivity();
- if (activity != null) {
- defaultCalendar = Utils.getSharedPreference(activity,
- GeneralPreferences.KEY_DEFAULT_CALENDAR, (String) null);
- } else {
- Log.e(TAG, "Activity is null, cannot load default calendar");
- }
-
- int calendarOwnerIndex = cursor.getColumnIndexOrThrow(Calendars.OWNER_ACCOUNT);
- int accountNameIndex = cursor.getColumnIndexOrThrow(Calendars.ACCOUNT_NAME);
- int accountTypeIndex = cursor.getColumnIndexOrThrow(Calendars.ACCOUNT_TYPE);
-
- cursor.moveToPosition(-1);
- while (cursor.moveToNext()) {
- String calendarOwner = cursor.getString(calendarOwnerIndex);
- if (defaultCalendar == null) {
- // There is no stored default upon the first time running. Use a primary
- // calendar in this case.
- if (calendarOwner != null &&
- calendarOwner.equals(cursor.getString(accountNameIndex)) &&
- !CalendarContract.ACCOUNT_TYPE_LOCAL.equals(
- cursor.getString(accountTypeIndex))) {
- setCalendarFields(cursor);
- return;
- }
- } else if (defaultCalendar.equals(calendarOwner)) {
- // Found the default calendar.
- setCalendarFields(cursor);
- return;
- }
- }
- cursor.moveToFirst();
- setCalendarFields(cursor);
- }
-
- private void setCalendarFields(Cursor cursor) {
- int calendarIdIndex = cursor.getColumnIndexOrThrow(Calendars._ID);
- int colorIndex = cursor.getColumnIndexOrThrow(Calendars.CALENDAR_COLOR);
- int calendarNameIndex = cursor.getColumnIndexOrThrow(Calendars.CALENDAR_DISPLAY_NAME);
- int accountNameIndex = cursor.getColumnIndexOrThrow(Calendars.ACCOUNT_NAME);
- int calendarOwnerIndex = cursor.getColumnIndexOrThrow(Calendars.OWNER_ACCOUNT);
-
- mCalendarId = cursor.getLong(calendarIdIndex);
- mCalendarOwner = cursor.getString(calendarOwnerIndex);
- mColor.setBackgroundColor(Utils.getDisplayColorFromColor(cursor
- .getInt(colorIndex)));
- String accountName = cursor.getString(accountNameIndex);
- String calendarName = cursor.getString(calendarNameIndex);
- mCalendarName.setText(calendarName);
- if (calendarName.equals(accountName)) {
- mAccountName.setVisibility(View.GONE);
- } else {
- mAccountName.setVisibility(View.VISIBLE);
- mAccountName.setText(accountName);
- }
- }
-}
diff --git a/src/com/android/calendar/event/EditEventActivity.java b/src/com/android/calendar/event/EditEventActivity.java
deleted file mode 100644
index 173a5735..00000000
--- a/src/com/android/calendar/event/EditEventActivity.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.calendar.event;
-
-import static android.provider.CalendarContract.EXTRA_EVENT_ALL_DAY;
-import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
-import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
-
-import android.app.ActionBar;
-import android.app.FragmentTransaction;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.CalendarContract.Events;
-import android.text.format.Time;
-import android.util.Log;
-import android.view.MenuItem;
-
-import com.android.calendar.AbstractCalendarActivity;
-import com.android.calendar.CalendarController;
-import com.android.calendar.CalendarController.EventInfo;
-import com.android.calendar.CalendarEventModel.ReminderEntry;
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-
-import java.util.ArrayList;
-
-public class EditEventActivity extends AbstractCalendarActivity {
- private static final String TAG = "EditEventActivity";
-
- private static final boolean DEBUG = false;
-
- private static final String BUNDLE_KEY_EVENT_ID = "key_event_id";
-
- public static final String EXTRA_EVENT_COLOR = "event_color";
-
- public static final String EXTRA_EVENT_REMINDERS = "reminders";
-
- private static boolean mIsMultipane;
-
- private EditEventFragment mEditFragment;
-
- private ArrayList<ReminderEntry> mReminders;
-
- private int mEventColor;
-
- private boolean mEventColorInitialized;
-
- private EventInfo mEventInfo;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- setContentView(R.layout.simple_frame_layout);
-
- mEventInfo = getEventInfoFromIntent(icicle);
- mReminders = getReminderEntriesFromIntent();
- mEventColorInitialized = getIntent().hasExtra(EXTRA_EVENT_COLOR);
- mEventColor = getIntent().getIntExtra(EXTRA_EVENT_COLOR, -1);
-
-
- mEditFragment = (EditEventFragment) getFragmentManager().findFragmentById(R.id.main_frame);
-
- mIsMultipane = Utils.getConfigBool(this, R.bool.multiple_pane_config);
-
- if (mIsMultipane) {
- getActionBar().setDisplayOptions(
- ActionBar.DISPLAY_SHOW_TITLE,
- ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME
- | ActionBar.DISPLAY_SHOW_TITLE);
- getActionBar().setTitle(
- mEventInfo.id == -1 ? R.string.event_create : R.string.event_edit);
- }
- else {
- getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
- ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME|
- ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
- }
-
- if (mEditFragment == null) {
- Intent intent = null;
- if (mEventInfo.id == -1) {
- intent = getIntent();
- }
-
- mEditFragment = new EditEventFragment(mEventInfo, mReminders, mEventColorInitialized,
- mEventColor, false, intent);
-
- mEditFragment.mShowModifyDialogOnLaunch = getIntent().getBooleanExtra(
- CalendarController.EVENT_EDIT_ON_LAUNCH, false);
-
- FragmentTransaction ft = getFragmentManager().beginTransaction();
- ft.replace(R.id.main_frame, mEditFragment);
- ft.show(mEditFragment);
- ft.commit();
- }
- }
-
- @SuppressWarnings("unchecked")
- private ArrayList<ReminderEntry> getReminderEntriesFromIntent() {
- Intent intent = getIntent();
- return (ArrayList<ReminderEntry>) intent.getSerializableExtra(EXTRA_EVENT_REMINDERS);
- }
-
- private EventInfo getEventInfoFromIntent(Bundle icicle) {
- EventInfo info = new EventInfo();
- long eventId = -1;
- Intent intent = getIntent();
- Uri data = intent.getData();
- if (data != null) {
- try {
- eventId = Long.parseLong(data.getLastPathSegment());
- } catch (NumberFormatException e) {
- if (DEBUG) {
- Log.d(TAG, "Create new event");
- }
- }
- } else if (icicle != null && icicle.containsKey(BUNDLE_KEY_EVENT_ID)) {
- eventId = icicle.getLong(BUNDLE_KEY_EVENT_ID);
- }
-
- boolean allDay = intent.getBooleanExtra(EXTRA_EVENT_ALL_DAY, false);
-
- long begin = intent.getLongExtra(EXTRA_EVENT_BEGIN_TIME, -1);
- long end = intent.getLongExtra(EXTRA_EVENT_END_TIME, -1);
- if (end != -1) {
- info.endTime = new Time();
- if (allDay) {
- info.endTime.timezone = Time.TIMEZONE_UTC;
- }
- info.endTime.set(end);
- }
- if (begin != -1) {
- info.startTime = new Time();
- if (allDay) {
- info.startTime.timezone = Time.TIMEZONE_UTC;
- }
- info.startTime.set(begin);
- }
- info.id = eventId;
- info.eventTitle = intent.getStringExtra(Events.TITLE);
- info.calendarId = intent.getLongExtra(Events.CALENDAR_ID, -1);
-
- if (allDay) {
- info.extraLong = CalendarController.EXTRA_CREATE_ALL_DAY;
- } else {
- info.extraLong = 0;
- }
- return info;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- Utils.returnToCalendarHome(this);
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-}
diff --git a/src/com/android/calendar/event/EditEventFragment.java b/src/com/android/calendar/event/EditEventFragment.java
deleted file mode 100644
index 2c966e94..00000000
--- a/src/com/android/calendar/event/EditEventFragment.java
+++ /dev/null
@@ -1,990 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.calendar.event;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Fragment;
-import android.app.FragmentManager;
-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.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.CalendarContract.Attendees;
-import android.provider.CalendarContract.Calendars;
-import android.provider.CalendarContract.Colors;
-import android.provider.CalendarContract.Events;
-import android.provider.CalendarContract.Reminders;
-import android.text.TextUtils;
-import android.text.format.Time;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.LinearLayout;
-import android.widget.Toast;
-
-import com.android.calendar.AsyncQueryService;
-import com.android.calendar.CalendarController;
-import com.android.calendar.CalendarController.EventHandler;
-import com.android.calendar.CalendarController.EventInfo;
-import com.android.calendar.CalendarController.EventType;
-import com.android.calendar.CalendarEventModel;
-import com.android.calendar.CalendarEventModel.Attendee;
-import com.android.calendar.CalendarEventModel.ReminderEntry;
-import com.android.calendar.DeleteEventHelper;
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-import com.android.colorpicker.ColorPickerSwatch.OnColorSelectedListener;
-import com.android.colorpicker.HsvColorComparator;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-
-public class EditEventFragment extends Fragment implements EventHandler, OnColorSelectedListener {
- private static final String TAG = "EditEventActivity";
- private static final String COLOR_PICKER_DIALOG_TAG = "ColorPickerDialog";
-
- private static final int REQUEST_CODE_COLOR_PICKER = 0;
-
- private static final String BUNDLE_KEY_MODEL = "key_model";
- private static final String BUNDLE_KEY_EDIT_STATE = "key_edit_state";
- private static final String BUNDLE_KEY_EVENT = "key_event";
- private static final String BUNDLE_KEY_READ_ONLY = "key_read_only";
- private static final String BUNDLE_KEY_EDIT_ON_LAUNCH = "key_edit_on_launch";
- private static final String BUNDLE_KEY_SHOW_COLOR_PALETTE = "show_color_palette";
-
- private static final String BUNDLE_KEY_DATE_BUTTON_CLICKED = "date_button_clicked";
-
- private static final boolean DEBUG = false;
-
- private static final int TOKEN_EVENT = 1;
- private static final int TOKEN_ATTENDEES = 1 << 1;
- private static final int TOKEN_REMINDERS = 1 << 2;
- private static final int TOKEN_CALENDARS = 1 << 3;
- private static final int TOKEN_COLORS = 1 << 4;
-
- private static final int TOKEN_ALL = TOKEN_EVENT | TOKEN_ATTENDEES | TOKEN_REMINDERS
- | TOKEN_CALENDARS | TOKEN_COLORS;
- private static final int TOKEN_UNITIALIZED = 1 << 31;
-
- /**
- * A bitfield of TOKEN_* to keep track which query hasn't been completed
- * yet. Once all queries have returned, the model can be applied to the
- * view.
- */
- private int mOutstandingQueries = TOKEN_UNITIALIZED;
-
- EditEventHelper mHelper;
- CalendarEventModel mModel;
- CalendarEventModel mOriginalModel;
- CalendarEventModel mRestoreModel;
- EditEventView mView;
- QueryHandler mHandler;
-
- private AlertDialog mModifyDialog;
- int mModification = Utils.MODIFY_UNINITIALIZED;
-
- private final EventInfo mEvent;
- private EventBundle mEventBundle;
- private ArrayList<ReminderEntry> mReminders;
- private int mEventColor;
- private boolean mEventColorInitialized = false;
- private Uri mUri;
- private long mBegin;
- private long mEnd;
- private long mCalendarId = -1;
-
- private EventColorPickerDialog mColorPickerDialog;
-
- private Activity mActivity;
- private final Done mOnDone = new Done();
-
- private boolean mSaveOnDetach = true;
- private boolean mIsReadOnly = false;
- public boolean mShowModifyDialogOnLaunch = false;
- private boolean mShowColorPalette = false;
-
- private boolean mTimeSelectedWasStartTime;
- private boolean mDateSelectedWasStartDate;
-
- private InputMethodManager mInputMethodManager;
-
- private final Intent mIntent;
-
- private boolean mUseCustomActionBar;
-
- private final View.OnClickListener mActionBarListener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- onActionBarItemSelected(v.getId());
- }
- };
-
- // TODO turn this into a helper function in EditEventHelper for building the
- // model
- private class QueryHandler extends AsyncQueryHandler {
- public QueryHandler(ContentResolver cr) {
- super(cr);
- }
-
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- // If the query didn't return a cursor for some reason return
- if (cursor == null) {
- return;
- }
-
- // If the Activity is finishing, then close the cursor.
- // Otherwise, use the new cursor in the adapter.
- final Activity activity = EditEventFragment.this.getActivity();
- if (activity == null || activity.isFinishing()) {
- cursor.close();
- return;
- }
- long eventId;
- switch (token) {
- case TOKEN_EVENT:
- if (cursor.getCount() == 0) {
- // The cursor is empty. This can happen if the event
- // was deleted.
- cursor.close();
- mOnDone.setDoneCode(Utils.DONE_EXIT);
- mSaveOnDetach = false;
- mOnDone.run();
- return;
- }
- mOriginalModel = new CalendarEventModel();
- EditEventHelper.setModelFromCursor(mOriginalModel, cursor);
- EditEventHelper.setModelFromCursor(mModel, cursor);
- cursor.close();
-
- mOriginalModel.mUri = mUri.toString();
-
- mModel.mUri = mUri.toString();
- mModel.mOriginalStart = mBegin;
- mModel.mOriginalEnd = mEnd;
- mModel.mIsFirstEventInSeries = mBegin == mOriginalModel.mStart;
- mModel.mStart = mBegin;
- mModel.mEnd = mEnd;
- if (mEventColorInitialized) {
- mModel.setEventColor(mEventColor);
- }
- eventId = mModel.mId;
-
- // TOKEN_ATTENDEES
- if (mModel.mHasAttendeeData && eventId != -1) {
- Uri attUri = Attendees.CONTENT_URI;
- String[] whereArgs = {
- Long.toString(eventId)
- };
- mHandler.startQuery(TOKEN_ATTENDEES, null, attUri,
- EditEventHelper.ATTENDEES_PROJECTION,
- EditEventHelper.ATTENDEES_WHERE /* selection */,
- whereArgs /* selection args */, null /* sort order */);
- } else {
- setModelIfDone(TOKEN_ATTENDEES);
- }
-
- // TOKEN_REMINDERS
- if (mModel.mHasAlarm && mReminders == null) {
- Uri rUri = Reminders.CONTENT_URI;
- String[] remArgs = {
- Long.toString(eventId)
- };
- mHandler.startQuery(TOKEN_REMINDERS, null, rUri,
- EditEventHelper.REMINDERS_PROJECTION,
- EditEventHelper.REMINDERS_WHERE /* selection */,
- remArgs /* selection args */, null /* sort order */);
- } else {
- if (mReminders == null) {
- // mReminders should not be null.
- mReminders = new ArrayList<ReminderEntry>();
- } else {
- Collections.sort(mReminders);
- }
- mOriginalModel.mReminders = mReminders;
- mModel.mReminders =
- (ArrayList<ReminderEntry>) mReminders.clone();
- setModelIfDone(TOKEN_REMINDERS);
- }
-
- // TOKEN_CALENDARS
- String[] selArgs = {
- Long.toString(mModel.mCalendarId)
- };
- mHandler.startQuery(TOKEN_CALENDARS, null, Calendars.CONTENT_URI,
- EditEventHelper.CALENDARS_PROJECTION, EditEventHelper.CALENDARS_WHERE,
- selArgs /* selection args */, null /* sort order */);
-
- // TOKEN_COLORS
- mHandler.startQuery(TOKEN_COLORS, null, Colors.CONTENT_URI,
- EditEventHelper.COLORS_PROJECTION,
- Colors.COLOR_TYPE + "=" + Colors.TYPE_EVENT, null, null);
-
- setModelIfDone(TOKEN_EVENT);
- break;
- case TOKEN_ATTENDEES:
- try {
- while (cursor.moveToNext()) {
- String name = cursor.getString(EditEventHelper.ATTENDEES_INDEX_NAME);
- String email = cursor.getString(EditEventHelper.ATTENDEES_INDEX_EMAIL);
- int status = cursor.getInt(EditEventHelper.ATTENDEES_INDEX_STATUS);
- int relationship = cursor
- .getInt(EditEventHelper.ATTENDEES_INDEX_RELATIONSHIP);
- if (relationship == Attendees.RELATIONSHIP_ORGANIZER) {
- if (email != null) {
- mModel.mOrganizer = email;
- mModel.mIsOrganizer = mModel.mOwnerAccount
- .equalsIgnoreCase(email);
- mOriginalModel.mOrganizer = email;
- mOriginalModel.mIsOrganizer = mOriginalModel.mOwnerAccount
- .equalsIgnoreCase(email);
- }
-
- if (TextUtils.isEmpty(name)) {
- mModel.mOrganizerDisplayName = mModel.mOrganizer;
- mOriginalModel.mOrganizerDisplayName =
- mOriginalModel.mOrganizer;
- } else {
- mModel.mOrganizerDisplayName = name;
- mOriginalModel.mOrganizerDisplayName = name;
- }
- }
-
- if (email != null) {
- if (mModel.mOwnerAccount != null &&
- mModel.mOwnerAccount.equalsIgnoreCase(email)) {
- int attendeeId =
- cursor.getInt(EditEventHelper.ATTENDEES_INDEX_ID);
- mModel.mOwnerAttendeeId = attendeeId;
- mModel.mSelfAttendeeStatus = status;
- mOriginalModel.mOwnerAttendeeId = attendeeId;
- mOriginalModel.mSelfAttendeeStatus = status;
- continue;
- }
- }
- Attendee attendee = new Attendee(name, email);
- attendee.mStatus = status;
- mModel.addAttendee(attendee);
- mOriginalModel.addAttendee(attendee);
- }
- } finally {
- cursor.close();
- }
-
- setModelIfDone(TOKEN_ATTENDEES);
- break;
- case TOKEN_REMINDERS:
- try {
- // Add all reminders to the models
- while (cursor.moveToNext()) {
- int minutes = cursor.getInt(EditEventHelper.REMINDERS_INDEX_MINUTES);
- int method = cursor.getInt(EditEventHelper.REMINDERS_INDEX_METHOD);
- ReminderEntry re = ReminderEntry.valueOf(minutes, method);
- mModel.mReminders.add(re);
- mOriginalModel.mReminders.add(re);
- }
-
- // Sort appropriately for display
- Collections.sort(mModel.mReminders);
- Collections.sort(mOriginalModel.mReminders);
- } finally {
- cursor.close();
- }
-
- setModelIfDone(TOKEN_REMINDERS);
- break;
- case TOKEN_CALENDARS:
- try {
- if (mModel.mId == -1) {
- // Populate Calendar spinner only if no event id is set.
- MatrixCursor matrixCursor = Utils.matrixCursorFromCursor(cursor);
- if (DEBUG) {
- Log.d(TAG, "onQueryComplete: setting cursor with "
- + matrixCursor.getCount() + " calendars");
- }
- mView.setCalendarsCursor(matrixCursor, isAdded() && isResumed(),
- mCalendarId);
- } else {
- // Populate model for an existing event
- EditEventHelper.setModelFromCalendarCursor(mModel, cursor);
- EditEventHelper.setModelFromCalendarCursor(mOriginalModel, cursor);
- }
- } finally {
- cursor.close();
- }
- setModelIfDone(TOKEN_CALENDARS);
- break;
- case TOKEN_COLORS:
- if (cursor.moveToFirst()) {
- EventColorCache cache = new EventColorCache();
- do
- {
- int colorKey = cursor.getInt(EditEventHelper.COLORS_INDEX_COLOR_KEY);
- int rawColor = cursor.getInt(EditEventHelper.COLORS_INDEX_COLOR);
- int displayColor = Utils.getDisplayColorFromColor(rawColor);
- String accountName = cursor
- .getString(EditEventHelper.COLORS_INDEX_ACCOUNT_NAME);
- String accountType = cursor
- .getString(EditEventHelper.COLORS_INDEX_ACCOUNT_TYPE);
- cache.insertColor(accountName, accountType,
- displayColor, colorKey);
- } while (cursor.moveToNext());
- cache.sortPalettes(new HsvColorComparator());
-
- mModel.mEventColorCache = cache;
- mView.mColorPickerNewEvent.setOnClickListener(mOnColorPickerClicked);
- mView.mColorPickerExistingEvent.setOnClickListener(mOnColorPickerClicked);
- }
- if (cursor != null) {
- cursor.close();
- }
-
- // If the account name/type is null, the calendar event colors cannot be
- // determined, so take the default/savedInstanceState value.
- if (mModel.mCalendarAccountName == null
- || mModel.mCalendarAccountType == null) {
- mView.setColorPickerButtonStates(mShowColorPalette);
- } else {
- mView.setColorPickerButtonStates(mModel.getCalendarEventColors());
- }
-
- setModelIfDone(TOKEN_COLORS);
- break;
- default:
- cursor.close();
- break;
- }
- }
- }
-
- private View.OnClickListener mOnColorPickerClicked = new View.OnClickListener() {
-
- @Override
- public void onClick(View v) {
- int[] colors = mModel.getCalendarEventColors();
- if (mColorPickerDialog == null) {
- mColorPickerDialog = EventColorPickerDialog.newInstance(colors,
- mModel.getEventColor(), mModel.getCalendarColor(), mView.mIsMultipane);
- mColorPickerDialog.setOnColorSelectedListener(EditEventFragment.this);
- } else {
- mColorPickerDialog.setCalendarColor(mModel.getCalendarColor());
- mColorPickerDialog.setColors(colors, mModel.getEventColor());
- }
- final FragmentManager fragmentManager = getFragmentManager();
- fragmentManager.executePendingTransactions();
- if (!mColorPickerDialog.isAdded()) {
- mColorPickerDialog.show(fragmentManager, COLOR_PICKER_DIALOG_TAG);
- }
- }
- };
-
- private void setModelIfDone(int queryType) {
- synchronized (this) {
- mOutstandingQueries &= ~queryType;
- if (mOutstandingQueries == 0) {
- if (mRestoreModel != null) {
- mModel = mRestoreModel;
- }
- if (mShowModifyDialogOnLaunch && mModification == Utils.MODIFY_UNINITIALIZED) {
- if (!TextUtils.isEmpty(mModel.mRrule)) {
- displayEditWhichDialog();
- } else {
- mModification = Utils.MODIFY_ALL;
- }
-
- }
- mView.setModel(mModel);
- mView.setModification(mModification);
- }
- }
- }
-
- public EditEventFragment() {
- this(null, null, false, -1, false, null);
- }
-
- public EditEventFragment(EventInfo event, ArrayList<ReminderEntry> reminders,
- boolean eventColorInitialized, int eventColor, boolean readOnly, Intent intent) {
- mEvent = event;
- mIsReadOnly = readOnly;
- mIntent = intent;
-
- mReminders = reminders;
- mEventColorInitialized = eventColorInitialized;
- if (eventColorInitialized) {
- mEventColor = eventColor;
- }
- setHasOptionsMenu(true);
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- mColorPickerDialog = (EventColorPickerDialog) getActivity().getFragmentManager()
- .findFragmentByTag(COLOR_PICKER_DIALOG_TAG);
- if (mColorPickerDialog != null) {
- mColorPickerDialog.setOnColorSelectedListener(this);
- }
- }
-
- private void startQuery() {
- mUri = null;
- mBegin = -1;
- mEnd = -1;
- if (mEvent != null) {
- if (mEvent.id != -1) {
- mModel.mId = mEvent.id;
- mUri = ContentUris.withAppendedId(Events.CONTENT_URI, mEvent.id);
- } else {
- // New event. All day?
- mModel.mAllDay = mEvent.extraLong == CalendarController.EXTRA_CREATE_ALL_DAY;
- }
- if (mEvent.startTime != null) {
- mBegin = mEvent.startTime.toMillis(true);
- }
- if (mEvent.endTime != null) {
- mEnd = mEvent.endTime.toMillis(true);
- }
- if (mEvent.calendarId != -1) {
- mCalendarId = mEvent.calendarId;
- }
- } else if (mEventBundle != null) {
- if (mEventBundle.id != -1) {
- mModel.mId = mEventBundle.id;
- mUri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventBundle.id);
- }
- mBegin = mEventBundle.start;
- mEnd = mEventBundle.end;
- }
-
- if (mReminders != null) {
- mModel.mReminders = mReminders;
- }
-
- if (mEventColorInitialized) {
- mModel.setEventColor(mEventColor);
- }
-
- if (mBegin <= 0) {
- // use a default value instead
- mBegin = mHelper.constructDefaultStartTime(System.currentTimeMillis());
- }
- if (mEnd < mBegin) {
- // use a default value instead
- mEnd = mHelper.constructDefaultEndTime(mBegin);
- }
-
- // Kick off the query for the event
- boolean newEvent = mUri == null;
- if (!newEvent) {
- mModel.mCalendarAccessLevel = Calendars.CAL_ACCESS_NONE;
- mOutstandingQueries = TOKEN_ALL;
- if (DEBUG) {
- Log.d(TAG, "startQuery: uri for event is " + mUri.toString());
- }
- mHandler.startQuery(TOKEN_EVENT, null, mUri, EditEventHelper.EVENT_PROJECTION,
- null /* selection */, null /* selection args */, null /* sort order */);
- } else {
- mOutstandingQueries = TOKEN_CALENDARS | TOKEN_COLORS;
- if (DEBUG) {
- Log.d(TAG, "startQuery: Editing a new event.");
- }
- mModel.mOriginalStart = mBegin;
- mModel.mOriginalEnd = mEnd;
- mModel.mStart = mBegin;
- mModel.mEnd = mEnd;
- mModel.mCalendarId = mCalendarId;
- mModel.mSelfAttendeeStatus = Attendees.ATTENDEE_STATUS_ACCEPTED;
-
- // Start a query in the background to read the list of calendars and colors
- mHandler.startQuery(TOKEN_CALENDARS, null, Calendars.CONTENT_URI,
- EditEventHelper.CALENDARS_PROJECTION,
- EditEventHelper.CALENDARS_WHERE_WRITEABLE_VISIBLE, null /* selection args */,
- null /* sort order */);
-
- mHandler.startQuery(TOKEN_COLORS, null, Colors.CONTENT_URI,
- EditEventHelper.COLORS_PROJECTION,
- Colors.COLOR_TYPE + "=" + Colors.TYPE_EVENT, null, null);
-
- mModification = Utils.MODIFY_ALL;
- mView.setModification(mModification);
- }
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- mActivity = activity;
-
- mHelper = new EditEventHelper(activity, null);
- mHandler = new QueryHandler(activity.getContentResolver());
- mModel = new CalendarEventModel(activity, mIntent);
- mInputMethodManager = (InputMethodManager)
- activity.getSystemService(Context.INPUT_METHOD_SERVICE);
-
- mUseCustomActionBar = !Utils.getConfigBool(mActivity, R.bool.multiple_pane_config);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
-// mContext.requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- View view;
- if (mIsReadOnly) {
- view = inflater.inflate(R.layout.edit_event_single_column, null);
- } else {
- view = inflater.inflate(R.layout.edit_event, null);
- }
- mView = new EditEventView(mActivity, view, mOnDone, mTimeSelectedWasStartTime,
- mDateSelectedWasStartDate);
- startQuery();
-
- if (mUseCustomActionBar) {
- View actionBarButtons = inflater.inflate(R.layout.edit_event_custom_actionbar,
- new LinearLayout(mActivity), false);
- View cancelActionView = actionBarButtons.findViewById(R.id.action_cancel);
- cancelActionView.setOnClickListener(mActionBarListener);
- View doneActionView = actionBarButtons.findViewById(R.id.action_done);
- doneActionView.setOnClickListener(mActionBarListener);
-
- mActivity.getActionBar().setCustomView(actionBarButtons);
- }
-
- return view;
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
-
- if (mUseCustomActionBar) {
- mActivity.getActionBar().setCustomView(null);
- }
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (savedInstanceState != null) {
- if (savedInstanceState.containsKey(BUNDLE_KEY_MODEL)) {
- mRestoreModel = (CalendarEventModel) savedInstanceState.getSerializable(
- BUNDLE_KEY_MODEL);
- }
- if (savedInstanceState.containsKey(BUNDLE_KEY_EDIT_STATE)) {
- mModification = savedInstanceState.getInt(BUNDLE_KEY_EDIT_STATE);
- }
- if (savedInstanceState.containsKey(BUNDLE_KEY_EDIT_ON_LAUNCH)) {
- mShowModifyDialogOnLaunch = savedInstanceState
- .getBoolean(BUNDLE_KEY_EDIT_ON_LAUNCH);
- }
- if (savedInstanceState.containsKey(BUNDLE_KEY_EVENT)) {
- mEventBundle = (EventBundle) savedInstanceState.getSerializable(BUNDLE_KEY_EVENT);
- }
- if (savedInstanceState.containsKey(BUNDLE_KEY_READ_ONLY)) {
- mIsReadOnly = savedInstanceState.getBoolean(BUNDLE_KEY_READ_ONLY);
- }
- if (savedInstanceState.containsKey("EditEventView_timebuttonclicked")) {
- mTimeSelectedWasStartTime = savedInstanceState.getBoolean(
- "EditEventView_timebuttonclicked");
- }
- if (savedInstanceState.containsKey(BUNDLE_KEY_DATE_BUTTON_CLICKED)) {
- mDateSelectedWasStartDate = savedInstanceState.getBoolean(
- BUNDLE_KEY_DATE_BUTTON_CLICKED);
- }
- if (savedInstanceState.containsKey(BUNDLE_KEY_SHOW_COLOR_PALETTE)) {
- mShowColorPalette = savedInstanceState.getBoolean(BUNDLE_KEY_SHOW_COLOR_PALETTE);
- }
-
- }
- }
-
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- super.onCreateOptionsMenu(menu, inflater);
-
- if (!mUseCustomActionBar) {
- inflater.inflate(R.menu.edit_event_title_bar, menu);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- return onActionBarItemSelected(item.getItemId());
- }
-
- /**
- * Handles menu item selections, whether they come from our custom action bar buttons or from
- * the standard menu items. Depends on the menu item ids matching the custom action bar button
- * ids.
- *
- * @param itemId the button or menu item id
- * @return whether the event was handled here
- */
- private boolean onActionBarItemSelected(int itemId) {
- if (itemId == R.id.action_done) {
- if (EditEventHelper.canModifyEvent(mModel) || EditEventHelper.canRespond(mModel)) {
- if (mView != null && mView.prepareForSave()) {
- if (mModification == Utils.MODIFY_UNINITIALIZED) {
- mModification = Utils.MODIFY_ALL;
- }
- mOnDone.setDoneCode(Utils.DONE_SAVE | Utils.DONE_EXIT);
- mOnDone.run();
- } else {
- mOnDone.setDoneCode(Utils.DONE_REVERT);
- mOnDone.run();
- }
- } else if (EditEventHelper.canAddReminders(mModel) && mModel.mId != -1
- && mOriginalModel != null && mView.prepareForSave()) {
- saveReminders();
- mOnDone.setDoneCode(Utils.DONE_EXIT);
- mOnDone.run();
- } else {
- mOnDone.setDoneCode(Utils.DONE_REVERT);
- mOnDone.run();
- }
- } else if (itemId == R.id.action_cancel) {
- mOnDone.setDoneCode(Utils.DONE_REVERT);
- mOnDone.run();
- }
- return true;
- }
-
- private void saveReminders() {
- ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(3);
- boolean changed = EditEventHelper.saveReminders(ops, mModel.mId, mModel.mReminders,
- mOriginalModel.mReminders, false /* no force save */);
-
- if (!changed) {
- return;
- }
-
- AsyncQueryService service = new AsyncQueryService(getActivity());
- service.startBatch(0, null, Calendars.CONTENT_URI.getAuthority(), ops, 0);
- // Update the "hasAlarm" field for the event
- Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mModel.mId);
- int len = mModel.mReminders.size();
- boolean hasAlarm = len > 0;
- if (hasAlarm != mOriginalModel.mHasAlarm) {
- ContentValues values = new ContentValues();
- values.put(Events.HAS_ALARM, hasAlarm ? 1 : 0);
- service.startUpdate(0, null, uri, values, null, null, 0);
- }
-
- Toast.makeText(mActivity, R.string.saving_event, Toast.LENGTH_SHORT).show();
- }
-
- protected void displayEditWhichDialog() {
- if (mModification == Utils.MODIFY_UNINITIALIZED) {
- final boolean notSynced = TextUtils.isEmpty(mModel.mSyncId);
- boolean isFirstEventInSeries = mModel.mIsFirstEventInSeries;
- int itemIndex = 0;
- CharSequence[] items;
-
- if (notSynced) {
- // If this event has not been synced, then don't allow deleting
- // or changing a single instance.
- if (isFirstEventInSeries) {
- // Still display the option so the user knows all events are
- // changing
- items = new CharSequence[1];
- } else {
- items = new CharSequence[2];
- }
- } else {
- if (isFirstEventInSeries) {
- items = new CharSequence[2];
- } else {
- items = new CharSequence[3];
- }
- items[itemIndex++] = mActivity.getText(R.string.modify_event);
- }
- items[itemIndex++] = mActivity.getText(R.string.modify_all);
-
- // Do one more check to make sure this remains at the end of the list
- if (!isFirstEventInSeries) {
- items[itemIndex++] = mActivity.getText(R.string.modify_all_following);
- }
-
- // Display the modification dialog.
- if (mModifyDialog != null) {
- mModifyDialog.dismiss();
- mModifyDialog = null;
- }
- mModifyDialog = new AlertDialog.Builder(mActivity).setTitle(R.string.edit_event_label)
- .setItems(items, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (which == 0) {
- // Update this if we start allowing exceptions
- // to unsynced events in the app
- mModification = notSynced ? Utils.MODIFY_ALL
- : Utils.MODIFY_SELECTED;
- if (mModification == Utils.MODIFY_SELECTED) {
- mModel.mOriginalSyncId = notSynced ? null : mModel.mSyncId;
- mModel.mOriginalId = mModel.mId;
- }
- } else if (which == 1) {
- mModification = notSynced ? Utils.MODIFY_ALL_FOLLOWING
- : Utils.MODIFY_ALL;
- } else if (which == 2) {
- mModification = Utils.MODIFY_ALL_FOLLOWING;
- }
-
- mView.setModification(mModification);
- }
- }).show();
-
- mModifyDialog.setOnCancelListener(new OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialog) {
- Activity a = EditEventFragment.this.getActivity();
- if (a != null) {
- a.finish();
- }
- }
- });
- }
- }
-
- class Done implements EditEventHelper.EditDoneRunnable {
- private int mCode = -1;
-
- @Override
- public void setDoneCode(int code) {
- mCode = code;
- }
-
- @Override
- public void run() {
- // We only want this to get called once, either because the user
- // pressed back/home or one of the buttons on screen
- mSaveOnDetach = false;
- if (mModification == Utils.MODIFY_UNINITIALIZED) {
- // If this is uninitialized the user hit back, the only
- // changeable item is response to default to all events.
- mModification = Utils.MODIFY_ALL;
- }
-
- if ((mCode & Utils.DONE_SAVE) != 0 && mModel != null
- && (EditEventHelper.canRespond(mModel)
- || EditEventHelper.canModifyEvent(mModel))
- && mView.prepareForSave()
- && !isEmptyNewEvent()
- && mModel.normalizeReminders()
- && mHelper.saveEvent(mModel, mOriginalModel, mModification)) {
- int stringResource;
- if (!mModel.mAttendeesList.isEmpty()) {
- if (mModel.mUri != null) {
- stringResource = R.string.saving_event_with_guest;
- } else {
- stringResource = R.string.creating_event_with_guest;
- }
- } else {
- if (mModel.mUri != null) {
- stringResource = R.string.saving_event;
- } else {
- stringResource = R.string.creating_event;
- }
- }
- Toast.makeText(mActivity, stringResource, Toast.LENGTH_SHORT).show();
- } else if ((mCode & Utils.DONE_SAVE) != 0 && mModel != null && isEmptyNewEvent()) {
- Toast.makeText(mActivity, R.string.empty_event, Toast.LENGTH_SHORT).show();
- }
-
- if ((mCode & Utils.DONE_DELETE) != 0 && mOriginalModel != null
- && EditEventHelper.canModifyCalendar(mOriginalModel)) {
- long begin = mModel.mStart;
- long end = mModel.mEnd;
- int which = -1;
- switch (mModification) {
- case Utils.MODIFY_SELECTED:
- which = DeleteEventHelper.DELETE_SELECTED;
- break;
- case Utils.MODIFY_ALL_FOLLOWING:
- which = DeleteEventHelper.DELETE_ALL_FOLLOWING;
- break;
- case Utils.MODIFY_ALL:
- which = DeleteEventHelper.DELETE_ALL;
- break;
- }
- DeleteEventHelper deleteHelper = new DeleteEventHelper(
- mActivity, mActivity, !mIsReadOnly /* exitWhenDone */);
- deleteHelper.delete(begin, end, mOriginalModel, which);
- }
-
- if ((mCode & Utils.DONE_EXIT) != 0) {
- // This will exit the edit event screen, should be called
- // when we want to return to the main calendar views
- if ((mCode & Utils.DONE_SAVE) != 0) {
- if (mActivity != null) {
- long start = mModel.mStart;
- long end = mModel.mEnd;
- if (mModel.mAllDay) {
- // For allday events we want to go to the day in the
- // user's current tz
- String tz = Utils.getTimeZone(mActivity, null);
- Time t = new Time(Time.TIMEZONE_UTC);
- t.set(start);
- t.timezone = tz;
- start = t.toMillis(true);
-
- t.timezone = Time.TIMEZONE_UTC;
- t.set(end);
- t.timezone = tz;
- end = t.toMillis(true);
- }
- CalendarController.getInstance(mActivity).launchViewEvent(-1, start, end,
- Attendees.ATTENDEE_STATUS_NONE);
- }
- }
- Activity a = EditEventFragment.this.getActivity();
- if (a != null) {
- a.finish();
- }
- }
-
- // Hide a software keyboard so that user won't see it even after this Fragment's
- // disappearing.
- final View focusedView = mActivity.getCurrentFocus();
- if (focusedView != null) {
- mInputMethodManager.hideSoftInputFromWindow(focusedView.getWindowToken(), 0);
- focusedView.clearFocus();
- }
- }
- }
-
- boolean isEmptyNewEvent() {
- if (mOriginalModel != null) {
- // Not new
- return false;
- }
-
- if (mModel.mOriginalStart != mModel.mStart || mModel.mOriginalEnd != mModel.mEnd) {
- return false;
- }
-
- if (!mModel.mAttendeesList.isEmpty()) {
- return false;
- }
-
- return mModel.isEmpty();
- }
-
- @Override
- public void onPause() {
- Activity act = getActivity();
- if (mSaveOnDetach && act != null && !mIsReadOnly && !act.isChangingConfigurations()
- && mView.prepareForSave()) {
- mOnDone.setDoneCode(Utils.DONE_SAVE);
- mOnDone.run();
- }
- super.onPause();
- }
-
- @Override
- public void onDestroy() {
- if (mView != null) {
- mView.setModel(null);
- }
- if (mModifyDialog != null) {
- mModifyDialog.dismiss();
- mModifyDialog = null;
- }
- super.onDestroy();
- }
-
- @Override
- public void eventsChanged() {
- // TODO Requery to see if event has changed
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- mView.prepareForSave();
- outState.putSerializable(BUNDLE_KEY_MODEL, mModel);
- outState.putInt(BUNDLE_KEY_EDIT_STATE, mModification);
- if (mEventBundle == null && mEvent != null) {
- mEventBundle = new EventBundle();
- mEventBundle.id = mEvent.id;
- if (mEvent.startTime != null) {
- mEventBundle.start = mEvent.startTime.toMillis(true);
- }
- if (mEvent.endTime != null) {
- mEventBundle.end = mEvent.startTime.toMillis(true);
- }
- }
- outState.putBoolean(BUNDLE_KEY_EDIT_ON_LAUNCH, mShowModifyDialogOnLaunch);
- outState.putSerializable(BUNDLE_KEY_EVENT, mEventBundle);
- outState.putBoolean(BUNDLE_KEY_READ_ONLY, mIsReadOnly);
- outState.putBoolean(BUNDLE_KEY_SHOW_COLOR_PALETTE, mView.isColorPaletteVisible());
-
- outState.putBoolean("EditEventView_timebuttonclicked", mView.mTimeSelectedWasStartTime);
- outState.putBoolean(BUNDLE_KEY_DATE_BUTTON_CLICKED, mView.mDateSelectedWasStartDate);
- }
-
- @Override
- public long getSupportedEventTypes() {
- return EventType.USER_HOME;
- }
-
- @Override
- public void handleEvent(EventInfo event) {
- // It's currently unclear if we want to save the event or not when home
- // is pressed. When creating a new event we shouldn't save since we
- // can't get the id of the new event easily.
- if ((false && event.eventType == EventType.USER_HOME) || (event.eventType == EventType.GO_TO
- && mSaveOnDetach)) {
- if (mView != null && mView.prepareForSave()) {
- mOnDone.setDoneCode(Utils.DONE_SAVE);
- mOnDone.run();
- }
- }
- }
-
- private static class EventBundle implements Serializable {
- private static final long serialVersionUID = 1L;
- long id = -1;
- long start = -1;
- long end = -1;
- }
-
- @Override
- public void onColorSelected(int color) {
- if (!mModel.isEventColorInitialized() || mModel.getEventColor() != color) {
- mModel.setEventColor(color);
- mView.updateHeadlineColor(mModel, color);
- }
- }
-}
diff --git a/src/com/android/calendar/event/EditEventHelper.java b/src/com/android/calendar/event/EditEventHelper.java
deleted file mode 100644
index c735e91e..00000000
--- a/src/com/android/calendar/event/EditEventHelper.java
+++ /dev/null
@@ -1,1390 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.calendar.event;
-
-import android.content.ContentProviderOperation;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.provider.CalendarContract.Attendees;
-import android.provider.CalendarContract.Calendars;
-import android.provider.CalendarContract.Colors;
-import android.provider.CalendarContract.Events;
-import android.provider.CalendarContract.Reminders;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-import android.text.util.Rfc822Token;
-import android.text.util.Rfc822Tokenizer;
-import android.util.Log;
-import android.view.View;
-
-import com.android.calendar.AbstractCalendarActivity;
-import com.android.calendar.AsyncQueryService;
-import com.android.calendar.CalendarEventModel;
-import com.android.calendar.CalendarEventModel.Attendee;
-import com.android.calendar.CalendarEventModel.ReminderEntry;
-import com.android.calendar.Utils;
-import com.android.calendarcommon2.DateException;
-import com.android.calendarcommon2.EventRecurrence;
-import com.android.calendarcommon2.RecurrenceProcessor;
-import com.android.calendarcommon2.RecurrenceSet;
-import com.android.common.Rfc822Validator;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.TimeZone;
-
-public class EditEventHelper {
- private static final String TAG = "EditEventHelper";
-
- private static final boolean DEBUG = false;
-
- // Used for parsing rrules for special cases.
- private EventRecurrence mEventRecurrence = new EventRecurrence();
-
- private static final String NO_EVENT_COLOR = "";
-
- public 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.DTEND, // 8
- Events.DURATION, // 9
- Events.EVENT_TIMEZONE, // 10
- Events.RRULE, // 11
- Events._SYNC_ID, // 12
- Events.AVAILABILITY, // 13
- Events.ACCESS_LEVEL, // 14
- Events.OWNER_ACCOUNT, // 15
- Events.HAS_ATTENDEE_DATA, // 16
- Events.ORIGINAL_SYNC_ID, // 17
- Events.ORGANIZER, // 18
- Events.GUESTS_CAN_MODIFY, // 19
- Events.ORIGINAL_ID, // 20
- Events.STATUS, // 21
- Events.CALENDAR_COLOR, // 22
- Events.EVENT_COLOR, // 23
- Events.EVENT_COLOR_KEY // 24
- };
- protected static final int EVENT_INDEX_ID = 0;
- protected static final int EVENT_INDEX_TITLE = 1;
- protected static final int EVENT_INDEX_DESCRIPTION = 2;
- protected static final int EVENT_INDEX_EVENT_LOCATION = 3;
- protected static final int EVENT_INDEX_ALL_DAY = 4;
- protected static final int EVENT_INDEX_HAS_ALARM = 5;
- protected static final int EVENT_INDEX_CALENDAR_ID = 6;
- protected static final int EVENT_INDEX_DTSTART = 7;
- protected static final int EVENT_INDEX_DTEND = 8;
- protected static final int EVENT_INDEX_DURATION = 9;
- protected static final int EVENT_INDEX_TIMEZONE = 10;
- protected static final int EVENT_INDEX_RRULE = 11;
- protected static final int EVENT_INDEX_SYNC_ID = 12;
- protected static final int EVENT_INDEX_AVAILABILITY = 13;
- protected static final int EVENT_INDEX_ACCESS_LEVEL = 14;
- protected static final int EVENT_INDEX_OWNER_ACCOUNT = 15;
- protected static final int EVENT_INDEX_HAS_ATTENDEE_DATA = 16;
- protected static final int EVENT_INDEX_ORIGINAL_SYNC_ID = 17;
- protected static final int EVENT_INDEX_ORGANIZER = 18;
- protected static final int EVENT_INDEX_GUESTS_CAN_MODIFY = 19;
- protected static final int EVENT_INDEX_ORIGINAL_ID = 20;
- protected static final int EVENT_INDEX_EVENT_STATUS = 21;
- protected static final int EVENT_INDEX_CALENDAR_COLOR = 22;
- protected static final int EVENT_INDEX_EVENT_COLOR = 23;
- protected static final int EVENT_INDEX_EVENT_COLOR_KEY = 24;
-
- public static final String[] REMINDERS_PROJECTION = new String[] {
- Reminders._ID, // 0
- Reminders.MINUTES, // 1
- Reminders.METHOD, // 2
- };
- public static final int REMINDERS_INDEX_MINUTES = 1;
- public static final int REMINDERS_INDEX_METHOD = 2;
- public static final String REMINDERS_WHERE = Reminders.EVENT_ID + "=?";
-
- // Visible for testing
- static final String ATTENDEES_DELETE_PREFIX = Attendees.EVENT_ID + "=? AND "
- + Attendees.ATTENDEE_EMAIL + " IN (";
-
- public static final int DOES_NOT_REPEAT = 0;
- public static final int REPEATS_DAILY = 1;
- public static final int REPEATS_EVERY_WEEKDAY = 2;
- public static final int REPEATS_WEEKLY_ON_DAY = 3;
- public static final int REPEATS_MONTHLY_ON_DAY_COUNT = 4;
- public static final int REPEATS_MONTHLY_ON_DAY = 5;
- public static final int REPEATS_YEARLY = 6;
- public static final int REPEATS_CUSTOM = 7;
-
- protected static final int MODIFY_UNINITIALIZED = 0;
- protected static final int MODIFY_SELECTED = 1;
- protected static final int MODIFY_ALL_FOLLOWING = 2;
- protected static final int MODIFY_ALL = 3;
-
- protected static final int DAY_IN_SECONDS = 24 * 60 * 60;
-
- private final AsyncQueryService mService;
-
- // This allows us to flag the event if something is wrong with it, right now
- // if an uri is provided for an event that doesn't exist in the db.
- protected boolean mEventOk = true;
-
- public static final int ATTENDEE_ID_NONE = -1;
- public static final int[] ATTENDEE_VALUES = {
- Attendees.ATTENDEE_STATUS_NONE,
- Attendees.ATTENDEE_STATUS_ACCEPTED,
- Attendees.ATTENDEE_STATUS_TENTATIVE,
- Attendees.ATTENDEE_STATUS_DECLINED,
- };
-
- /**
- * This is the symbolic name for the key used to pass in the boolean for
- * creating all-day events that is part of the extra data of the intent.
- * This is used only for creating new events and is set to true if the
- * default for the new event should be an all-day event.
- */
- public static final String EVENT_ALL_DAY = "allDay";
-
- static final String[] CALENDARS_PROJECTION = new String[] {
- Calendars._ID, // 0
- Calendars.CALENDAR_DISPLAY_NAME, // 1
- Calendars.OWNER_ACCOUNT, // 2
- Calendars.CALENDAR_COLOR, // 3
- Calendars.CAN_ORGANIZER_RESPOND, // 4
- Calendars.CALENDAR_ACCESS_LEVEL, // 5
- Calendars.VISIBLE, // 6
- Calendars.MAX_REMINDERS, // 7
- Calendars.ALLOWED_REMINDERS, // 8
- Calendars.ALLOWED_ATTENDEE_TYPES, // 9
- Calendars.ALLOWED_AVAILABILITY, // 10
- Calendars.ACCOUNT_NAME, // 11
- Calendars.ACCOUNT_TYPE, //12
- };
- static final int CALENDARS_INDEX_ID = 0;
- static final int CALENDARS_INDEX_DISPLAY_NAME = 1;
- static final int CALENDARS_INDEX_OWNER_ACCOUNT = 2;
- static final int CALENDARS_INDEX_COLOR = 3;
- static final int CALENDARS_INDEX_CAN_ORGANIZER_RESPOND = 4;
- static final int CALENDARS_INDEX_ACCESS_LEVEL = 5;
- static final int CALENDARS_INDEX_VISIBLE = 6;
- static final int CALENDARS_INDEX_MAX_REMINDERS = 7;
- static final int CALENDARS_INDEX_ALLOWED_REMINDERS = 8;
- static final int CALENDARS_INDEX_ALLOWED_ATTENDEE_TYPES = 9;
- static final int CALENDARS_INDEX_ALLOWED_AVAILABILITY = 10;
- static final int CALENDARS_INDEX_ACCOUNT_NAME = 11;
- static final int CALENDARS_INDEX_ACCOUNT_TYPE = 12;
-
- static final String CALENDARS_WHERE_WRITEABLE_VISIBLE = Calendars.CALENDAR_ACCESS_LEVEL + ">="
- + Calendars.CAL_ACCESS_CONTRIBUTOR + " AND " + Calendars.VISIBLE + "=1";
-
- static final String CALENDARS_WHERE = Calendars._ID + "=?";
-
- static final String[] COLORS_PROJECTION = new String[] {
- Colors._ID, // 0
- Colors.ACCOUNT_NAME,
- Colors.ACCOUNT_TYPE,
- Colors.COLOR, // 1
- Colors.COLOR_KEY // 2
- };
-
- static final String COLORS_WHERE = Colors.ACCOUNT_NAME + "=? AND " + Colors.ACCOUNT_TYPE +
- "=? AND " + Colors.COLOR_TYPE + "=" + Colors.TYPE_EVENT;
-
- static final int COLORS_INDEX_ACCOUNT_NAME = 1;
- static final int COLORS_INDEX_ACCOUNT_TYPE = 2;
- static final int COLORS_INDEX_COLOR = 3;
- static final int COLORS_INDEX_COLOR_KEY = 4;
-
- static final String[] ATTENDEES_PROJECTION = new String[] {
- Attendees._ID, // 0
- Attendees.ATTENDEE_NAME, // 1
- Attendees.ATTENDEE_EMAIL, // 2
- Attendees.ATTENDEE_RELATIONSHIP, // 3
- Attendees.ATTENDEE_STATUS, // 4
- };
- static final int ATTENDEES_INDEX_ID = 0;
- static final int ATTENDEES_INDEX_NAME = 1;
- static final int ATTENDEES_INDEX_EMAIL = 2;
- static final int ATTENDEES_INDEX_RELATIONSHIP = 3;
- static final int ATTENDEES_INDEX_STATUS = 4;
- static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=? AND attendeeEmail IS NOT NULL";
-
- public static class AttendeeItem {
- public boolean mRemoved;
- public Attendee mAttendee;
- public Drawable mBadge;
- public int mUpdateCounts;
- public View mView;
- public Uri mContactLookupUri;
-
- public AttendeeItem(Attendee attendee, Drawable badge) {
- mAttendee = attendee;
- mBadge = badge;
- }
- }
-
- public EditEventHelper(Context context) {
- mService = ((AbstractCalendarActivity)context).getAsyncQueryService();
- }
-
- public EditEventHelper(Context context, CalendarEventModel model) {
- this(context);
- // TODO: Remove unnecessary constructor.
- }
-
- /**
- * Saves the event. Returns true if the event was successfully saved, false
- * otherwise.
- *
- * @param model The event model to save
- * @param originalModel A model of the original event if it exists
- * @param modifyWhich For recurring events which type of series modification to use
- * @return true if the event was successfully queued for saving
- */
- public boolean saveEvent(CalendarEventModel model, CalendarEventModel originalModel,
- int modifyWhich) {
- boolean forceSaveReminders = false;
-
- if (DEBUG) {
- Log.d(TAG, "Saving event model: " + model);
- }
-
- if (!mEventOk) {
- if (DEBUG) {
- Log.w(TAG, "Event no longer exists. Event was not saved.");
- }
- return false;
- }
-
- // It's a problem if we try to save a non-existent or invalid model or if we're
- // modifying an existing event and we have the wrong original model
- if (model == null) {
- Log.e(TAG, "Attempted to save null model.");
- return false;
- }
- if (!model.isValid()) {
- Log.e(TAG, "Attempted to save invalid model.");
- return false;
- }
- if (originalModel != null && !isSameEvent(model, originalModel)) {
- Log.e(TAG, "Attempted to update existing event but models didn't refer to the same "
- + "event.");
- return false;
- }
- if (originalModel != null && model.isUnchanged(originalModel)) {
- return false;
- }
-
- ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
- int eventIdIndex = -1;
-
- ContentValues values = getContentValuesFromModel(model);
-
- if (model.mUri != null && originalModel == null) {
- Log.e(TAG, "Existing event but no originalModel provided. Aborting save.");
- return false;
- }
- Uri uri = null;
- if (model.mUri != null) {
- uri = Uri.parse(model.mUri);
- }
-
- // Update the "hasAlarm" field for the event
- ArrayList<ReminderEntry> reminders = model.mReminders;
- int len = reminders.size();
- values.put(Events.HAS_ALARM, (len > 0) ? 1 : 0);
-
- if (uri == null) {
- // Add hasAttendeeData for a new event
- values.put(Events.HAS_ATTENDEE_DATA, 1);
- values.put(Events.STATUS, Events.STATUS_CONFIRMED);
- eventIdIndex = ops.size();
- ContentProviderOperation.Builder b = ContentProviderOperation.newInsert(
- Events.CONTENT_URI).withValues(values);
- ops.add(b.build());
- forceSaveReminders = true;
-
- } else if (TextUtils.isEmpty(model.mRrule) && TextUtils.isEmpty(originalModel.mRrule)) {
- // Simple update to a non-recurring event
- checkTimeDependentFields(originalModel, model, values, modifyWhich);
- ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());
-
- } else if (TextUtils.isEmpty(originalModel.mRrule)) {
- // This event was changed from a non-repeating event to a
- // repeating event.
- ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());
-
- } else if (modifyWhich == MODIFY_SELECTED) {
- // Modify contents of the current instance of repeating event
- // Create a recurrence exception
- long begin = model.mOriginalStart;
- values.put(Events.ORIGINAL_SYNC_ID, originalModel.mSyncId);
- values.put(Events.ORIGINAL_INSTANCE_TIME, begin);
- boolean allDay = originalModel.mAllDay;
- values.put(Events.ORIGINAL_ALL_DAY, allDay ? 1 : 0);
- values.put(Events.STATUS, originalModel.mEventStatus);
-
- eventIdIndex = ops.size();
- ContentProviderOperation.Builder b = ContentProviderOperation.newInsert(
- Events.CONTENT_URI).withValues(values);
- ops.add(b.build());
- forceSaveReminders = true;
-
- } else if (modifyWhich == MODIFY_ALL_FOLLOWING) {
-
- if (TextUtils.isEmpty(model.mRrule)) {
- // We've changed a recurring event to a non-recurring event.
- // If the event we are editing is the first in the series,
- // then delete the whole series. Otherwise, update the series
- // to end at the new start time.
- if (isFirstEventInSeries(model, originalModel)) {
- ops.add(ContentProviderOperation.newDelete(uri).build());
- } else {
- // Update the current repeating event to end at the new start time. We
- // ignore the RRULE returned because the exception event doesn't want one.
- updatePastEvents(ops, originalModel, model.mOriginalStart);
- }
- eventIdIndex = ops.size();
- values.put(Events.STATUS, originalModel.mEventStatus);
- ops.add(ContentProviderOperation.newInsert(Events.CONTENT_URI).withValues(values)
- .build());
- } else {
- if (isFirstEventInSeries(model, originalModel)) {
- checkTimeDependentFields(originalModel, model, values, modifyWhich);
- ContentProviderOperation.Builder b = ContentProviderOperation.newUpdate(uri)
- .withValues(values);
- ops.add(b.build());
- } else {
- // We need to update the existing recurrence to end before the exception
- // event starts. If the recurrence rule has a COUNT, we need to adjust
- // that in the original and in the exception. This call rewrites the
- // original event's recurrence rule (in "ops"), and returns a new rule
- // for the exception. If the exception explicitly set a new rule, however,
- // we don't want to overwrite it.
- String newRrule = updatePastEvents(ops, originalModel, model.mOriginalStart);
- if (model.mRrule.equals(originalModel.mRrule)) {
- values.put(Events.RRULE, newRrule);
- }
-
- // Create a new event with the user-modified fields
- eventIdIndex = ops.size();
- values.put(Events.STATUS, originalModel.mEventStatus);
- ops.add(ContentProviderOperation.newInsert(Events.CONTENT_URI).withValues(
- values).build());
- }
- }
- forceSaveReminders = true;
-
- } else if (modifyWhich == MODIFY_ALL) {
-
- // Modify all instances of repeating event
- if (TextUtils.isEmpty(model.mRrule)) {
- // We've changed a recurring event to a non-recurring event.
- // Delete the whole series and replace it with a new
- // non-recurring event.
- ops.add(ContentProviderOperation.newDelete(uri).build());
-
- eventIdIndex = ops.size();
- ops.add(ContentProviderOperation.newInsert(Events.CONTENT_URI).withValues(values)
- .build());
- forceSaveReminders = true;
- } else {
- checkTimeDependentFields(originalModel, model, values, modifyWhich);
- ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());
- }
- }
-
- // New Event or New Exception to an existing event
- boolean newEvent = (eventIdIndex != -1);
- ArrayList<ReminderEntry> originalReminders;
- if (originalModel != null) {
- originalReminders = originalModel.mReminders;
- } else {
- originalReminders = new ArrayList<ReminderEntry>();
- }
-
- if (newEvent) {
- saveRemindersWithBackRef(ops, eventIdIndex, reminders, originalReminders,
- forceSaveReminders);
- } else if (uri != null) {
- long eventId = ContentUris.parseId(uri);
- saveReminders(ops, eventId, reminders, originalReminders, forceSaveReminders);
- }
-
- ContentProviderOperation.Builder b;
- boolean hasAttendeeData = model.mHasAttendeeData;
-
- if (hasAttendeeData && model.mOwnerAttendeeId == -1) {
- // Organizer is not an attendee
-
- String ownerEmail = model.mOwnerAccount;
- if (model.mAttendeesList.size() != 0 && Utils.isValidEmail(ownerEmail)) {
- // Add organizer as attendee since we got some attendees
-
- values.clear();
- values.put(Attendees.ATTENDEE_EMAIL, ownerEmail);
- values.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ORGANIZER);
- values.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED);
- values.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_ACCEPTED);
-
- if (newEvent) {
- b = ContentProviderOperation.newInsert(Attendees.CONTENT_URI)
- .withValues(values);
- b.withValueBackReference(Attendees.EVENT_ID, eventIdIndex);
- } else {
- values.put(Attendees.EVENT_ID, model.mId);
- b = ContentProviderOperation.newInsert(Attendees.CONTENT_URI)
- .withValues(values);
- }
- ops.add(b.build());
- }
- } else if (hasAttendeeData &&
- model.mSelfAttendeeStatus != originalModel.mSelfAttendeeStatus &&
- model.mOwnerAttendeeId != -1) {
- if (DEBUG) {
- Log.d(TAG, "Setting attendee status to " + model.mSelfAttendeeStatus);
- }
- Uri attUri = ContentUris.withAppendedId(Attendees.CONTENT_URI, model.mOwnerAttendeeId);
-
- values.clear();
- values.put(Attendees.ATTENDEE_STATUS, model.mSelfAttendeeStatus);
- values.put(Attendees.EVENT_ID, model.mId);
- b = ContentProviderOperation.newUpdate(attUri).withValues(values);
- 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 (hasAttendeeData && (newEvent || uri != null)) {
- String attendees = model.getAttendeesString();
- String originalAttendeesString;
- if (originalModel != null) {
- originalAttendeesString = originalModel.getAttendeesString();
- } else {
- originalAttendeesString = "";
- }
- // Hit the content provider only if this is a new event or the user
- // has changed it
- if (newEvent || !TextUtils.equals(originalAttendeesString, attendees)) {
- // 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).
- HashMap<String, Attendee> newAttendees = model.mAttendeesList;
- LinkedList<String> removedAttendees = new LinkedList<String>();
-
- // 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) {
- removedAttendees.clear();
- HashMap<String, Attendee> originalAttendees = originalModel.mAttendeesList;
- for (String originalEmail : originalAttendees.keySet()) {
- if (newAttendees.containsKey(originalEmail)) {
- // existing attendee. remove from new attendees set.
- newAttendees.remove(originalEmail);
- } else {
- // no longer in attendees. mark as removed.
- removedAttendees.add(originalEmail);
- }
- }
-
- // delete removed attendees if necessary
- if (removedAttendees.size() > 0) {
- 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 (String removedAttendee : removedAttendees) {
- if (i > 1) {
- deleteWhere.append(",");
- }
- deleteWhere.append("?");
- args[i++] = removedAttendee;
- }
- deleteWhere.append(")");
- b.withSelection(deleteWhere.toString(), args);
- ops.add(b.build());
- }
- }
-
- if (newAttendees.size() > 0) {
- // Insert the new attendees
- for (Attendee attendee : newAttendees.values()) {
- values.clear();
- values.put(Attendees.ATTENDEE_NAME, attendee.mName);
- values.put(Attendees.ATTENDEE_EMAIL, attendee.mEmail);
- values.put(Attendees.ATTENDEE_RELATIONSHIP,
- Attendees.RELATIONSHIP_ATTENDEE);
- values.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED);
- 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());
- }
- }
- }
- }
-
-
- mService.startBatch(mService.getNextToken(), null, android.provider.CalendarContract.AUTHORITY, ops,
- Utils.UNDO_DELAY);
-
- return true;
- }
-
- public static LinkedHashSet<Rfc822Token> getAddressesFromList(String list,
- Rfc822Validator validator) {
- LinkedHashSet<Rfc822Token> addresses = new LinkedHashSet<Rfc822Token>();
- Rfc822Tokenizer.tokenize(list, addresses);
- if (validator == null) {
- return addresses;
- }
-
- // validate the emails, out of paranoia. they should already be
- // validated on input, but drop any invalid emails just to be safe.
- Iterator<Rfc822Token> addressIterator = addresses.iterator();
- while (addressIterator.hasNext()) {
- Rfc822Token address = addressIterator.next();
- if (!validator.isValid(address.getAddress())) {
- Log.v(TAG, "Dropping invalid attendee email address: " + address.getAddress());
- addressIterator.remove();
- }
- }
- return addresses;
- }
-
- /**
- * When we aren't given an explicit start time, we default to the next
- * upcoming half hour. So, for example, 5:01 -> 5:30, 5:30 -> 6:00, etc.
- *
- * @return a UTC time in milliseconds representing the next upcoming half
- * hour
- */
- protected long constructDefaultStartTime(long now) {
- Time defaultStart = new Time();
- defaultStart.set(now);
- defaultStart.second = 0;
- defaultStart.minute = 30;
- long defaultStartMillis = defaultStart.toMillis(false);
- if (now < defaultStartMillis) {
- return defaultStartMillis;
- } else {
- return defaultStartMillis + 30 * DateUtils.MINUTE_IN_MILLIS;
- }
- }
-
- /**
- * When we aren't given an explicit end time, we default to an hour after
- * the start time.
- * @param startTime the start time
- * @return a default end time
- */
- protected long constructDefaultEndTime(long startTime) {
- return startTime + DateUtils.HOUR_IN_MILLIS;
- }
-
- // TODO think about how useful this is. Probably check if our event has
- // changed early on and either update all or nothing. Should still do the if
- // MODIFY_ALL bit.
- void checkTimeDependentFields(CalendarEventModel originalModel, CalendarEventModel model,
- ContentValues values, int modifyWhich) {
- long oldBegin = model.mOriginalStart;
- long oldEnd = model.mOriginalEnd;
- boolean oldAllDay = originalModel.mAllDay;
- String oldRrule = originalModel.mRrule;
- String oldTimezone = originalModel.mTimezone;
-
- long newBegin = model.mStart;
- long newEnd = model.mEnd;
- boolean newAllDay = model.mAllDay;
- String newRrule = model.mRrule;
- String newTimezone = model.mTimezone;
-
- // If none of the time-dependent fields changed, then remove them.
- if (oldBegin == newBegin && oldEnd == newEnd && oldAllDay == newAllDay
- && TextUtils.equals(oldRrule, newRrule)
- && TextUtils.equals(oldTimezone, newTimezone)) {
- values.remove(Events.DTSTART);
- values.remove(Events.DTEND);
- values.remove(Events.DURATION);
- values.remove(Events.ALL_DAY);
- values.remove(Events.RRULE);
- values.remove(Events.EVENT_TIMEZONE);
- return;
- }
-
- if (TextUtils.isEmpty(oldRrule) || TextUtils.isEmpty(newRrule)) {
- return;
- }
-
- // If we are modifying all events then we need to set DTSTART to the
- // start time of the first event in the series, not the current
- // date and time. If the start time of the event was changed
- // (from, say, 3pm to 4pm), then we want to add the time difference
- // to the start time of the first event in the series (the DTSTART
- // value). If we are modifying one instance or all following instances,
- // then we leave the DTSTART field alone.
- if (modifyWhich == MODIFY_ALL) {
- long oldStartMillis = originalModel.mStart;
- if (oldBegin != newBegin) {
- // The user changed the start time of this event
- long offset = newBegin - oldBegin;
- oldStartMillis += offset;
- }
- if (newAllDay) {
- Time time = new Time(Time.TIMEZONE_UTC);
- time.set(oldStartMillis);
- time.hour = 0;
- time.minute = 0;
- time.second = 0;
- oldStartMillis = time.toMillis(false);
- }
- values.put(Events.DTSTART, oldStartMillis);
- }
- }
-
- /**
- * Prepares an update to the original event so it stops where the new series
- * begins. When we update 'this and all following' events we need to change
- * the original event to end before a new series starts. This creates an
- * update to the old event's rrule to do that.
- *<p>
- * If the event's recurrence rule has a COUNT, we also need to reduce the count in the
- * RRULE for the exception event.
- *
- * @param ops The list of operations to add the update to
- * @param originalModel The original event that we're updating
- * @param endTimeMillis The time before which the event must end (i.e. the start time of the
- * exception event instance).
- * @return A replacement exception recurrence rule.
- */
- public String updatePastEvents(ArrayList<ContentProviderOperation> ops,
- CalendarEventModel originalModel, long endTimeMillis) {
- boolean origAllDay = originalModel.mAllDay;
- String origRrule = originalModel.mRrule;
- String newRrule = origRrule;
-
- EventRecurrence origRecurrence = new EventRecurrence();
- origRecurrence.parse(origRrule);
-
- // Get the start time of the first instance in the original recurrence.
- long startTimeMillis = originalModel.mStart;
- Time dtstart = new Time();
- dtstart.timezone = originalModel.mTimezone;
- dtstart.set(startTimeMillis);
-
- ContentValues updateValues = new ContentValues();
-
- if (origRecurrence.count > 0) {
- /*
- * Generate the full set of instances for this recurrence, from the first to the
- * one just before endTimeMillis. The list should never be empty, because this method
- * should not be called for the first instance. All we're really interested in is
- * the *number* of instances found.
- *
- * TODO: the model assumes RRULE and ignores RDATE, EXRULE, and EXDATE. For the
- * current environment this is reasonable, but that may not hold in the future.
- *
- * TODO: if COUNT is 1, should we convert the event to non-recurring? e.g. we
- * do an "edit this and all future events" on the 2nd instances.
- */
- RecurrenceSet recurSet = new RecurrenceSet(originalModel.mRrule, null, null, null);
- RecurrenceProcessor recurProc = new RecurrenceProcessor();
- long[] recurrences;
- try {
- recurrences = recurProc.expand(dtstart, recurSet, startTimeMillis, endTimeMillis);
- } catch (DateException de) {
- throw new RuntimeException(de);
- }
-
- if (recurrences.length == 0) {
- throw new RuntimeException("can't use this method on first instance");
- }
-
- EventRecurrence excepRecurrence = new EventRecurrence();
- excepRecurrence.parse(origRrule); // TODO: add+use a copy constructor instead
- excepRecurrence.count -= recurrences.length;
- newRrule = excepRecurrence.toString();
-
- origRecurrence.count = recurrences.length;
-
- } else {
- // The "until" time must be in UTC time in order for Google calendar
- // to display it properly. For all-day events, the "until" time string
- // must include just the date field, and not the time field. The
- // repeating events repeat up to and including the "until" time.
- Time untilTime = new Time();
- untilTime.timezone = Time.TIMEZONE_UTC;
-
- // Subtract one second from the old begin time to get the new
- // "until" time.
- untilTime.set(endTimeMillis - 1000); // subtract one second (1000 millis)
- if (origAllDay) {
- untilTime.hour = 0;
- untilTime.minute = 0;
- untilTime.second = 0;
- untilTime.allDay = true;
- untilTime.normalize(false);
-
- // This should no longer be necessary -- DTSTART should already be in the correct
- // format for an all-day event.
- dtstart.hour = 0;
- dtstart.minute = 0;
- dtstart.second = 0;
- dtstart.allDay = true;
- dtstart.timezone = Time.TIMEZONE_UTC;
- }
- origRecurrence.until = untilTime.format2445();
- }
-
- updateValues.put(Events.RRULE, origRecurrence.toString());
- updateValues.put(Events.DTSTART, dtstart.normalize(true));
- ContentProviderOperation.Builder b =
- ContentProviderOperation.newUpdate(Uri.parse(originalModel.mUri))
- .withValues(updateValues);
- ops.add(b.build());
-
- return newRrule;
- }
-
- /**
- * Compares two models to ensure that they refer to the same event. This is
- * a safety check to make sure an updated event model refers to the same
- * event as the original model. If the original model is null then this is a
- * new event or we're forcing an overwrite so we return true in that case.
- * The important identifiers are the Calendar Id and the Event Id.
- *
- * @return
- */
- public static boolean isSameEvent(CalendarEventModel model, CalendarEventModel originalModel) {
- if (originalModel == null) {
- return true;
- }
-
- if (model.mCalendarId != originalModel.mCalendarId) {
- return false;
- }
- if (model.mId != originalModel.mId) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Saves the reminders, if they changed. Returns true if operations to
- * update the database were added.
- *
- * @param ops the array of ContentProviderOperations
- * @param eventId the id of the event whose reminders are being updated
- * @param reminders the array of reminders set by the user
- * @param originalReminders the original array of reminders
- * @param forceSave if true, then save the reminders even if they didn't change
- * @return true if operations to update the database were added
- */
- public static boolean saveReminders(ArrayList<ContentProviderOperation> ops, long eventId,
- ArrayList<ReminderEntry> reminders, ArrayList<ReminderEntry> originalReminders,
- boolean forceSave) {
- // If the reminders have not changed, then don't update the database
- if (reminders.equals(originalReminders) && !forceSave) {
- return false;
- }
-
- // Delete all the existing reminders for this event
- String where = Reminders.EVENT_ID + "=?";
- String[] args = new String[] {Long.toString(eventId)};
- ContentProviderOperation.Builder b = ContentProviderOperation
- .newDelete(Reminders.CONTENT_URI);
- b.withSelection(where, args);
- ops.add(b.build());
-
- ContentValues values = new ContentValues();
- int len = reminders.size();
-
- // Insert the new reminders, if any
- for (int i = 0; i < len; i++) {
- ReminderEntry re = reminders.get(i);
-
- values.clear();
- values.put(Reminders.MINUTES, re.getMinutes());
- values.put(Reminders.METHOD, re.getMethod());
- values.put(Reminders.EVENT_ID, eventId);
- b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(values);
- ops.add(b.build());
- }
- return true;
- }
-
- /**
- * Saves the reminders, if they changed. Returns true if operations to
- * update the database were added. Uses a reference id since an id isn't
- * created until the row is added.
- *
- * @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
- * @param forceSave if true, then save the reminders even if they didn't change
- * @return true if operations to update the database were added
- */
- public static boolean saveRemindersWithBackRef(ArrayList<ContentProviderOperation> ops,
- int eventIdIndex, ArrayList<ReminderEntry> reminders,
- ArrayList<ReminderEntry> originalReminders, boolean forceSave) {
- // If the reminders have not changed, then don't update the database
- if (reminders.equals(originalReminders) && !forceSave) {
- return false;
- }
-
- // Delete all the existing reminders for this event
- ContentProviderOperation.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 = reminders.size();
-
- // Insert the new reminders, if any
- for (int i = 0; i < len; i++) {
- ReminderEntry re = reminders.get(i);
-
- values.clear();
- values.put(Reminders.MINUTES, re.getMinutes());
- values.put(Reminders.METHOD, re.getMethod());
- b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(values);
- b.withValueBackReference(Reminders.EVENT_ID, eventIdIndex);
- ops.add(b.build());
- }
- return true;
- }
-
- // It's the first event in the series if the start time before being
- // modified is the same as the original event's start time
- static boolean isFirstEventInSeries(CalendarEventModel model,
- CalendarEventModel originalModel) {
- return model.mOriginalStart == originalModel.mStart;
- }
-
- // Adds an rRule and duration to a set of content values
- void addRecurrenceRule(ContentValues values, CalendarEventModel model) {
- String rrule = model.mRrule;
-
- values.put(Events.RRULE, rrule);
- long end = model.mEnd;
- long start = model.mStart;
- String duration = model.mDuration;
-
- boolean isAllDay = model.mAllDay;
- if (end >= start) {
- if (isAllDay) {
- // if it's all day compute the duration in days
- long days = (end - start + DateUtils.DAY_IN_MILLIS - 1)
- / DateUtils.DAY_IN_MILLIS;
- duration = "P" + days + "D";
- } else {
- // otherwise compute the duration in seconds
- long seconds = (end - start) / DateUtils.SECOND_IN_MILLIS;
- duration = "P" + seconds + "S";
- }
- } else if (TextUtils.isEmpty(duration)) {
-
- // If no good duration info exists assume the default
- if (isAllDay) {
- duration = "P1D";
- } else {
- duration = "P3600S";
- }
- }
- // recurring events should have a duration and dtend set to null
- values.put(Events.DURATION, duration);
- values.put(Events.DTEND, (Long) null);
- }
-
- /**
- * Uses the recurrence selection and the model data to build an rrule and
- * write it to the model.
- *
- * @param selection the type of rrule
- * @param model The event to update
- * @param weekStart the week start day, specified as java.util.Calendar
- * constants
- */
- static void updateRecurrenceRule(int selection, CalendarEventModel model,
- int weekStart) {
- // Make sure we don't have any leftover data from the previous setting
- EventRecurrence eventRecurrence = new EventRecurrence();
-
- if (selection == DOES_NOT_REPEAT) {
- model.mRrule = null;
- return;
- } else if (selection == REPEATS_CUSTOM) {
- // Keep custom recurrence as before.
- return;
- } else if (selection == REPEATS_DAILY) {
- eventRecurrence.freq = EventRecurrence.DAILY;
- } else if (selection == REPEATS_EVERY_WEEKDAY) {
- eventRecurrence.freq = EventRecurrence.WEEKLY;
- int dayCount = 5;
- int[] byday = new int[dayCount];
- int[] bydayNum = new int[dayCount];
-
- byday[0] = EventRecurrence.MO;
- byday[1] = EventRecurrence.TU;
- byday[2] = EventRecurrence.WE;
- byday[3] = EventRecurrence.TH;
- byday[4] = EventRecurrence.FR;
- for (int day = 0; day < dayCount; day++) {
- bydayNum[day] = 0;
- }
-
- eventRecurrence.byday = byday;
- eventRecurrence.bydayNum = bydayNum;
- eventRecurrence.bydayCount = dayCount;
- } else if (selection == REPEATS_WEEKLY_ON_DAY) {
- eventRecurrence.freq = EventRecurrence.WEEKLY;
- int[] days = new int[1];
- int dayCount = 1;
- int[] dayNum = new int[dayCount];
- Time startTime = new Time(model.mTimezone);
- startTime.set(model.mStart);
-
- days[0] = EventRecurrence.timeDay2Day(startTime.weekDay);
- // not sure why this needs to be zero, but set it for now.
- dayNum[0] = 0;
-
- eventRecurrence.byday = days;
- eventRecurrence.bydayNum = dayNum;
- eventRecurrence.bydayCount = dayCount;
- } else if (selection == REPEATS_MONTHLY_ON_DAY) {
- eventRecurrence.freq = EventRecurrence.MONTHLY;
- eventRecurrence.bydayCount = 0;
- eventRecurrence.bymonthdayCount = 1;
- int[] bymonthday = new int[1];
- Time startTime = new Time(model.mTimezone);
- startTime.set(model.mStart);
- bymonthday[0] = startTime.monthDay;
- eventRecurrence.bymonthday = bymonthday;
- } else if (selection == REPEATS_MONTHLY_ON_DAY_COUNT) {
- eventRecurrence.freq = EventRecurrence.MONTHLY;
- eventRecurrence.bydayCount = 1;
- eventRecurrence.bymonthdayCount = 0;
-
- int[] byday = new int[1];
- int[] bydayNum = new int[1];
- Time startTime = new Time(model.mTimezone);
- startTime.set(model.mStart);
- // Compute the week number (for example, the "2nd" Monday)
- int dayCount = 1 + ((startTime.monthDay - 1) / 7);
- if (dayCount == 5) {
- dayCount = -1;
- }
- bydayNum[0] = dayCount;
- byday[0] = EventRecurrence.timeDay2Day(startTime.weekDay);
- eventRecurrence.byday = byday;
- eventRecurrence.bydayNum = bydayNum;
- } else if (selection == REPEATS_YEARLY) {
- eventRecurrence.freq = EventRecurrence.YEARLY;
- }
-
- // Set the week start day.
- eventRecurrence.wkst = EventRecurrence.calendarDay2Day(weekStart);
- model.mRrule = eventRecurrence.toString();
- }
-
- /**
- * Uses an event cursor to fill in the given model This method assumes the
- * cursor used {@link #EVENT_PROJECTION} as it's query projection. It uses
- * the cursor to fill in the given model with all the information available.
- *
- * @param model The model to fill in
- * @param cursor An event cursor that used {@link #EVENT_PROJECTION} for the query
- */
- public static void setModelFromCursor(CalendarEventModel model, Cursor cursor) {
- if (model == null || cursor == null || cursor.getCount() != 1) {
- Log.wtf(TAG, "Attempted to build non-existent model or from an incorrect query.");
- return;
- }
-
- model.clear();
- cursor.moveToFirst();
-
- model.mId = cursor.getInt(EVENT_INDEX_ID);
- model.mTitle = cursor.getString(EVENT_INDEX_TITLE);
- model.mDescription = cursor.getString(EVENT_INDEX_DESCRIPTION);
- model.mLocation = cursor.getString(EVENT_INDEX_EVENT_LOCATION);
- model.mAllDay = cursor.getInt(EVENT_INDEX_ALL_DAY) != 0;
- model.mHasAlarm = cursor.getInt(EVENT_INDEX_HAS_ALARM) != 0;
- model.mCalendarId = cursor.getInt(EVENT_INDEX_CALENDAR_ID);
- model.mStart = cursor.getLong(EVENT_INDEX_DTSTART);
- String tz = cursor.getString(EVENT_INDEX_TIMEZONE);
- if (!TextUtils.isEmpty(tz)) {
- model.mTimezone = tz;
- }
- String rRule = cursor.getString(EVENT_INDEX_RRULE);
- model.mRrule = rRule;
- model.mSyncId = cursor.getString(EVENT_INDEX_SYNC_ID);
- model.mAvailability = cursor.getInt(EVENT_INDEX_AVAILABILITY);
- int accessLevel = cursor.getInt(EVENT_INDEX_ACCESS_LEVEL);
- model.mOwnerAccount = cursor.getString(EVENT_INDEX_OWNER_ACCOUNT);
- model.mHasAttendeeData = cursor.getInt(EVENT_INDEX_HAS_ATTENDEE_DATA) != 0;
- model.mOriginalSyncId = cursor.getString(EVENT_INDEX_ORIGINAL_SYNC_ID);
- model.mOriginalId = cursor.getLong(EVENT_INDEX_ORIGINAL_ID);
- model.mOrganizer = cursor.getString(EVENT_INDEX_ORGANIZER);
- model.mIsOrganizer = model.mOwnerAccount.equalsIgnoreCase(model.mOrganizer);
- model.mGuestsCanModify = cursor.getInt(EVENT_INDEX_GUESTS_CAN_MODIFY) != 0;
-
- int rawEventColor;
- if (cursor.isNull(EVENT_INDEX_EVENT_COLOR)) {
- rawEventColor = cursor.getInt(EVENT_INDEX_CALENDAR_COLOR);
- } else {
- rawEventColor = cursor.getInt(EVENT_INDEX_EVENT_COLOR);
- }
- model.setEventColor(Utils.getDisplayColorFromColor(rawEventColor));
-
- if (accessLevel > 0) {
- // For now the array contains the values 0, 2, and 3. We subtract
- // one to make it easier to handle in code as 0,1,2.
- // Default (0), Private (1), Public (2)
- accessLevel--;
- }
- model.mAccessLevel = accessLevel;
- model.mEventStatus = cursor.getInt(EVENT_INDEX_EVENT_STATUS);
-
- boolean hasRRule = !TextUtils.isEmpty(rRule);
-
- // We expect only one of these, so ignore the other
- if (hasRRule) {
- model.mDuration = cursor.getString(EVENT_INDEX_DURATION);
- } else {
- model.mEnd = cursor.getLong(EVENT_INDEX_DTEND);
- }
-
- model.mModelUpdatedWithEventCursor = true;
- }
-
- /**
- * Uses a calendar cursor to fill in the given model This method assumes the
- * cursor used {@link #CALENDARS_PROJECTION} as it's query projection. It uses
- * the cursor to fill in the given model with all the information available.
- *
- * @param model The model to fill in
- * @param cursor An event cursor that used {@link #CALENDARS_PROJECTION} for the query
- * @return returns true if model was updated with the info in the cursor.
- */
- public static boolean setModelFromCalendarCursor(CalendarEventModel model, Cursor cursor) {
- if (model == null || cursor == null) {
- Log.wtf(TAG, "Attempted to build non-existent model or from an incorrect query.");
- return false;
- }
-
- if (model.mCalendarId == -1) {
- return false;
- }
-
- if (!model.mModelUpdatedWithEventCursor) {
- Log.wtf(TAG,
- "Can't update model with a Calendar cursor until it has seen an Event cursor.");
- return false;
- }
-
- cursor.moveToPosition(-1);
- while (cursor.moveToNext()) {
- if (model.mCalendarId != cursor.getInt(CALENDARS_INDEX_ID)) {
- continue;
- }
-
- model.mOrganizerCanRespond = cursor.getInt(CALENDARS_INDEX_CAN_ORGANIZER_RESPOND) != 0;
-
- model.mCalendarAccessLevel = cursor.getInt(CALENDARS_INDEX_ACCESS_LEVEL);
- model.mCalendarDisplayName = cursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
- model.setCalendarColor(Utils.getDisplayColorFromColor(
- cursor.getInt(CALENDARS_INDEX_COLOR)));
-
- model.mCalendarAccountName = cursor.getString(CALENDARS_INDEX_ACCOUNT_NAME);
- model.mCalendarAccountType = cursor.getString(CALENDARS_INDEX_ACCOUNT_TYPE);
-
- model.mCalendarMaxReminders = cursor.getInt(CALENDARS_INDEX_MAX_REMINDERS);
- model.mCalendarAllowedReminders = cursor.getString(CALENDARS_INDEX_ALLOWED_REMINDERS);
- model.mCalendarAllowedAttendeeTypes = cursor
- .getString(CALENDARS_INDEX_ALLOWED_ATTENDEE_TYPES);
- model.mCalendarAllowedAvailability = cursor
- .getString(CALENDARS_INDEX_ALLOWED_AVAILABILITY);
-
- return true;
- }
- return false;
- }
-
- public static boolean canModifyEvent(CalendarEventModel model) {
- return canModifyCalendar(model)
- && (model.mIsOrganizer || model.mGuestsCanModify);
- }
-
- public static boolean canModifyCalendar(CalendarEventModel model) {
- return model.mCalendarAccessLevel >= Calendars.CAL_ACCESS_CONTRIBUTOR
- || model.mCalendarId == -1;
- }
-
- public static boolean canAddReminders(CalendarEventModel model) {
- return model.mCalendarAccessLevel >= Calendars.CAL_ACCESS_READ;
- }
-
- public static boolean canRespond(CalendarEventModel model) {
- // For non-organizers, write permission to the calendar is sufficient.
- // For organizers, the user needs a) write permission to the calendar
- // AND b) ownerCanRespond == true AND c) attendee data exist
- // (this means num of attendees > 1, the calendar owner's and others).
- // Note that mAttendeeList omits the organizer.
-
- // (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 (!canModifyCalendar(model)) {
- return false;
- }
-
- if (!model.mIsOrganizer) {
- return true;
- }
-
- if (!model.mOrganizerCanRespond) {
- return false;
- }
-
- // This means we don't have the attendees data so we can't send
- // the list of attendees and the status back to the server
- if (model.mHasAttendeeData && model.mAttendeesList.size() == 0) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Goes through an event model and fills in content values for saving. This
- * method will perform the initial collection of values from the model and
- * put them into a set of ContentValues. It performs some basic work such as
- * fixing the time on allDay events and choosing whether to use an rrule or
- * dtend.
- *
- * @param model The complete model of the event you want to save
- * @return values
- */
- ContentValues getContentValuesFromModel(CalendarEventModel model) {
- String title = model.mTitle;
- boolean isAllDay = model.mAllDay;
- String rrule = model.mRrule;
- String timezone = model.mTimezone;
- if (timezone == null) {
- timezone = TimeZone.getDefault().getID();
- }
- Time startTime = new Time(timezone);
- Time endTime = new Time(timezone);
-
- startTime.set(model.mStart);
- endTime.set(model.mEnd);
- offsetStartTimeIfNecessary(startTime, endTime, rrule, model);
-
- ContentValues values = new ContentValues();
-
- long startMillis;
- long endMillis;
- long calendarId = model.mCalendarId;
- if (isAllDay) {
- // Reset start and end time, ensure at least 1 day duration, and set
- // the timezone to UTC, as required for all-day events.
- timezone = Time.TIMEZONE_UTC;
- startTime.hour = 0;
- startTime.minute = 0;
- startTime.second = 0;
- startTime.timezone = timezone;
- startMillis = startTime.normalize(true);
-
- endTime.hour = 0;
- endTime.minute = 0;
- endTime.second = 0;
- endTime.timezone = timezone;
- endMillis = endTime.normalize(true);
- if (endMillis < startMillis + DateUtils.DAY_IN_MILLIS) {
- // EditEventView#fillModelFromUI() should treat this case, but we want to ensure
- // the condition anyway.
- endMillis = startMillis + DateUtils.DAY_IN_MILLIS;
- }
- } else {
- startMillis = startTime.toMillis(true);
- endMillis = endTime.toMillis(true);
- }
-
- values.put(Events.CALENDAR_ID, calendarId);
- values.put(Events.EVENT_TIMEZONE, timezone);
- values.put(Events.TITLE, title);
- values.put(Events.ALL_DAY, isAllDay ? 1 : 0);
- values.put(Events.DTSTART, startMillis);
- values.put(Events.RRULE, rrule);
- if (!TextUtils.isEmpty(rrule)) {
- addRecurrenceRule(values, model);
- } else {
- values.put(Events.DURATION, (String) null);
- values.put(Events.DTEND, endMillis);
- }
- if (model.mDescription != null) {
- values.put(Events.DESCRIPTION, model.mDescription.trim());
- } else {
- values.put(Events.DESCRIPTION, (String) null);
- }
- if (model.mLocation != null) {
- values.put(Events.EVENT_LOCATION, model.mLocation.trim());
- } else {
- values.put(Events.EVENT_LOCATION, (String) null);
- }
- values.put(Events.AVAILABILITY, model.mAvailability);
- values.put(Events.HAS_ATTENDEE_DATA, model.mHasAttendeeData ? 1 : 0);
-
- int accessLevel = model.mAccessLevel;
- if (accessLevel > 0) {
- // For now the array contains the values 0, 2, and 3. We add one to match.
- // Default (0), Private (2), Public (3)
- accessLevel++;
- }
- values.put(Events.ACCESS_LEVEL, accessLevel);
- values.put(Events.STATUS, model.mEventStatus);
- if (model.isEventColorInitialized()) {
- if (model.getEventColor() == model.getCalendarColor()) {
- values.put(Events.EVENT_COLOR_KEY, NO_EVENT_COLOR);
- } else {
- values.put(Events.EVENT_COLOR_KEY, model.getEventColorKey());
- }
- }
- return values;
- }
-
- /**
- * If the recurrence rule is such that the event start date doesn't actually fall in one of the
- * recurrences, then push the start date up to the first actual instance of the event.
- */
- private void offsetStartTimeIfNecessary(Time startTime, Time endTime, String rrule,
- CalendarEventModel model) {
- if (rrule == null || rrule.isEmpty()) {
- // No need to waste any time with the parsing if the rule is empty.
- return;
- }
-
- mEventRecurrence.parse(rrule);
- // Check if we meet the specific special case. It has to:
- // * be weekly
- // * not recur on the same day of the week that the startTime falls on
- // In this case, we'll need to push the start time to fall on the first day of the week
- // that is part of the recurrence.
- if (mEventRecurrence.freq != EventRecurrence.WEEKLY) {
- // Not weekly so nothing to worry about.
- return;
- }
- if (mEventRecurrence.byday == null ||
- mEventRecurrence.byday.length > mEventRecurrence.bydayCount) {
- // This shouldn't happen, but just in case something is weird about the recurrence.
- return;
- }
-
- // Start to figure out what the nearest weekday is.
- int closestWeekday = Integer.MAX_VALUE;
- int weekstart = EventRecurrence.day2TimeDay(mEventRecurrence.wkst);
- int startDay = startTime.weekDay;
- for (int i = 0; i < mEventRecurrence.bydayCount; i++) {
- int day = EventRecurrence.day2TimeDay(mEventRecurrence.byday[i]);
- if (day == startDay) {
- // Our start day is one of the recurring days, so we're good.
- return;
- }
-
- if (day < weekstart) {
- // Let's not make any assumptions about what weekstart can be.
- day += 7;
- }
- // We either want the earliest day that is later in the week than startDay ...
- if (day > startDay && (day < closestWeekday || closestWeekday < startDay)) {
- closestWeekday = day;
- }
- // ... or if there are no days later than startDay, we want the earliest day that is
- // earlier in the week than startDay.
- if (closestWeekday == Integer.MAX_VALUE || closestWeekday < startDay) {
- // We haven't found a day that's later in the week than startDay yet.
- if (day < closestWeekday) {
- closestWeekday = day;
- }
- }
- }
-
- // We're here, so unfortunately our event's start day is not included in the days of
- // the week of the recurrence. To save this event correctly we'll need to push the start
- // date to the closest weekday that *is* part of the recurrence.
- if (closestWeekday < startDay) {
- closestWeekday += 7;
- }
- int daysOffset = closestWeekday - startDay;
- startTime.monthDay += daysOffset;
- endTime.monthDay += daysOffset;
- long newStartTime = startTime.normalize(true);
- long newEndTime = endTime.normalize(true);
-
- // Later we'll actually be using the values from the model rather than the startTime
- // and endTime themselves, so we need to make these changes to the model as well.
- model.mStart = newStartTime;
- model.mEnd = newEndTime;
- }
-
- /**
- * Takes an e-mail address and returns the domain (everything after the last @)
- */
- public static String extractDomain(String email) {
- int separator = email.lastIndexOf('@');
- if (separator != -1 && ++separator < email.length()) {
- return email.substring(separator);
- }
- return null;
- }
-
- public interface EditDoneRunnable extends Runnable {
- public void setDoneCode(int code);
- }
-}
diff --git a/src/com/android/calendar/event/EditEventView.java b/src/com/android/calendar/event/EditEventView.java
deleted file mode 100644
index a06774b8..00000000
--- a/src/com/android/calendar/event/EditEventView.java
+++ /dev/null
@@ -1,1852 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.calendar.event;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.DialogFragment;
-import android.app.FragmentManager;
-import android.app.ProgressDialog;
-import android.app.Service;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.provider.CalendarContract;
-import android.provider.CalendarContract.Attendees;
-import android.provider.CalendarContract.Calendars;
-import android.provider.CalendarContract.Events;
-import android.provider.CalendarContract.Reminders;
-import android.provider.Settings;
-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.Rfc822Tokenizer;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.inputmethod.EditorInfo;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ArrayAdapter;
-import android.widget.AutoCompleteTextView;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.LinearLayout;
-import android.widget.MultiAutoCompleteTextView;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-import android.widget.ResourceCursorAdapter;
-import android.widget.ScrollView;
-import android.widget.Spinner;
-import android.widget.TextView;
-import android.widget.TextView.OnEditorActionListener;
-
-import com.android.calendar.CalendarEventModel;
-import com.android.calendar.CalendarEventModel.Attendee;
-import com.android.calendar.CalendarEventModel.ReminderEntry;
-import com.android.calendar.EmailAddressAdapter;
-import com.android.calendar.EventInfoFragment;
-import com.android.calendar.EventRecurrenceFormatter;
-import com.android.calendar.GeneralPreferences;
-import com.android.calendar.R;
-import com.android.calendar.RecipientAdapter;
-import com.android.calendar.Utils;
-import com.android.calendar.event.EditEventHelper.EditDoneRunnable;
-import com.android.calendar.recurrencepicker.RecurrencePickerDialog;
-import com.android.calendarcommon2.EventRecurrence;
-import com.android.common.Rfc822InputFilter;
-import com.android.common.Rfc822Validator;
-import com.android.datetimepicker.date.DatePickerDialog;
-import com.android.datetimepicker.date.DatePickerDialog.OnDateSetListener;
-import com.android.datetimepicker.time.RadialPickerLayout;
-import com.android.datetimepicker.time.TimePickerDialog;
-import com.android.datetimepicker.time.TimePickerDialog.OnTimeSetListener;
-import com.android.ex.chips.AccountSpecifier;
-import com.android.ex.chips.BaseRecipientAdapter;
-import com.android.ex.chips.ChipsUtil;
-import com.android.ex.chips.RecipientEditTextView;
-import com.android.timezonepicker.TimeZoneInfo;
-import com.android.timezonepicker.TimeZonePickerDialog;
-import com.android.timezonepicker.TimeZonePickerUtils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Formatter;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.TimeZone;
-
-public class EditEventView implements View.OnClickListener, DialogInterface.OnCancelListener,
- DialogInterface.OnClickListener, OnItemSelectedListener,
- RecurrencePickerDialog.OnRecurrenceSetListener,
- TimeZonePickerDialog.OnTimeZoneSetListener {
-
- private static final String TAG = "EditEvent";
- private static final String GOOGLE_SECONDARY_CALENDAR = "calendar.google.com";
- private static final String PERIOD_SPACE = ". ";
-
- private static final String FRAG_TAG_DATE_PICKER = "datePickerDialogFragment";
- private static final String FRAG_TAG_TIME_PICKER = "timePickerDialogFragment";
- private static final String FRAG_TAG_TIME_ZONE_PICKER = "timeZonePickerDialogFragment";
- private static final String FRAG_TAG_RECUR_PICKER = "recurrencePickerDialogFragment";
-
- ArrayList<View> mEditOnlyList = new ArrayList<View>();
- ArrayList<View> mEditViewList = new ArrayList<View>();
- ArrayList<View> mViewOnlyList = new ArrayList<View>();
- TextView mLoadingMessage;
- ScrollView mScrollView;
- Button mStartDateButton;
- Button mEndDateButton;
- Button mStartTimeButton;
- Button mEndTimeButton;
- Button mTimezoneButton;
- View mColorPickerNewEvent;
- View mColorPickerExistingEvent;
- OnClickListener mChangeColorOnClickListener;
- View mTimezoneRow;
- TextView mStartTimeHome;
- TextView mStartDateHome;
- TextView mEndTimeHome;
- TextView mEndDateHome;
- CheckBox mAllDayCheckBox;
- Spinner mCalendarsSpinner;
- Button mRruleButton;
- Spinner mAvailabilitySpinner;
- Spinner mAccessLevelSpinner;
- RadioGroup mResponseRadioGroup;
- TextView mTitleTextView;
- AutoCompleteTextView mLocationTextView;
- EventLocationAdapter mLocationAdapter;
- TextView mDescriptionTextView;
- TextView mWhenView;
- TextView mTimezoneTextView;
- TextView mTimezoneLabel;
- LinearLayout mRemindersContainer;
- MultiAutoCompleteTextView mAttendeesList;
- View mCalendarSelectorGroup;
- View mCalendarSelectorWrapper;
- View mCalendarStaticGroup;
- View mLocationGroup;
- View mDescriptionGroup;
- View mRemindersGroup;
- View mResponseGroup;
- View mOrganizerGroup;
- View mAttendeesGroup;
- View mStartHomeGroup;
- View mEndHomeGroup;
-
- private int[] mOriginalPadding = new int[4];
-
- public boolean mIsMultipane;
- private ProgressDialog mLoadingCalendarsDialog;
- private AlertDialog mNoCalendarsDialog;
- private DialogFragment mTimezoneDialog;
- private Activity mActivity;
- private EditDoneRunnable mDone;
- private View mView;
- private CalendarEventModel mModel;
- private Cursor mCalendarsCursor;
- private AccountSpecifier mAddressAdapter;
- private Rfc822Validator mEmailValidator;
-
- public boolean mTimeSelectedWasStartTime;
- public boolean mDateSelectedWasStartDate;
- private TimePickerDialog mStartTimePickerDialog;
- private TimePickerDialog mEndTimePickerDialog;
- private DatePickerDialog mDatePickerDialog;
-
- /**
- * Contents of the "minutes" spinner. This has default values from the XML file, augmented
- * with any additional values that were already associated with the event.
- */
- private ArrayList<Integer> mReminderMinuteValues;
- private ArrayList<String> mReminderMinuteLabels;
-
- /**
- * Contents of the "methods" spinner. The "values" list specifies the method constant
- * (e.g. {@link Reminders#METHOD_ALERT}) associated with the labels. Any methods that
- * aren't allowed by the Calendar will be removed.
- */
- private ArrayList<Integer> mReminderMethodValues;
- private ArrayList<String> mReminderMethodLabels;
-
- /**
- * Contents of the "availability" spinner. The "values" list specifies the
- * type constant (e.g. {@link Events#AVAILABILITY_BUSY}) associated with the
- * labels. Any types that aren't allowed by the Calendar will be removed.
- */
- private ArrayList<Integer> mAvailabilityValues;
- private ArrayList<String> mAvailabilityLabels;
- private ArrayList<String> mOriginalAvailabilityLabels;
- private ArrayAdapter<String> mAvailabilityAdapter;
- private boolean mAvailabilityExplicitlySet;
- private boolean mAllDayChangingAvailability;
- private int mAvailabilityCurrentlySelected;
-
- private int mDefaultReminderMinutes;
-
- private boolean mSaveAfterQueryComplete = false;
-
- private TimeZonePickerUtils mTzPickerUtils;
- private Time mStartTime;
- private Time mEndTime;
- private String mTimezone;
- private boolean mAllDay = false;
- private int mModification = EditEventHelper.MODIFY_UNINITIALIZED;
-
- private EventRecurrence mEventRecurrence = new EventRecurrence();
-
- private ArrayList<LinearLayout> mReminderItems = new ArrayList<LinearLayout>(0);
- private ArrayList<ReminderEntry> mUnsupportedReminders = new ArrayList<ReminderEntry>();
- private String mRrule;
-
- private static StringBuilder mSB = new StringBuilder(50);
- private static Formatter mF = new Formatter(mSB, Locale.getDefault());
-
- /* This class is used to update the time buttons. */
- private class TimeListener implements OnTimeSetListener {
- private View mView;
-
- public TimeListener(View view) {
- mView = view;
- }
-
- @Override
- public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute) {
- // Cache the member variables locally to avoid inner class overhead.
- Time startTime = mStartTime;
- Time endTime = mEndTime;
-
- // Cache the start and end millis so that we limit the number
- // of calls to normalize() and toMillis(), which are fairly
- // expensive.
- long startMillis;
- long endMillis;
- if (mView == mStartTimeButton) {
- // The start time was changed.
- int hourDuration = endTime.hour - startTime.hour;
- int minuteDuration = endTime.minute - startTime.minute;
-
- startTime.hour = hourOfDay;
- startTime.minute = minute;
- startMillis = startTime.normalize(true);
-
- // Also update the end time to keep the duration constant.
- endTime.hour = hourOfDay + hourDuration;
- endTime.minute = minute + minuteDuration;
-
- // Update tz in case the start time switched from/to DLS
- populateTimezone(startMillis);
- } else {
- // The end time was changed.
- startMillis = startTime.toMillis(true);
- endTime.hour = hourOfDay;
- endTime.minute = minute;
-
- // Move to the start time if the end time is before the start
- // time.
- if (endTime.before(startTime)) {
- endTime.monthDay = startTime.monthDay + 1;
- }
- // Call populateTimezone if we support end time zone as well
- }
-
- endMillis = endTime.normalize(true);
-
- setDate(mEndDateButton, endMillis);
- setTime(mStartTimeButton, startMillis);
- setTime(mEndTimeButton, endMillis);
- updateHomeTime();
- }
- }
-
- private class TimeClickListener implements View.OnClickListener {
- private Time mTime;
-
- public TimeClickListener(Time time) {
- mTime = time;
- }
-
- @Override
- public void onClick(View v) {
-
- TimePickerDialog dialog;
- if (v == mStartTimeButton) {
- mTimeSelectedWasStartTime = true;
- if (mStartTimePickerDialog == null) {
- mStartTimePickerDialog = TimePickerDialog.newInstance(new TimeListener(v),
- mTime.hour, mTime.minute, DateFormat.is24HourFormat(mActivity));
- } else {
- mStartTimePickerDialog.setStartTime(mTime.hour, mTime.minute);
- }
- dialog = mStartTimePickerDialog;
- } else {
- mTimeSelectedWasStartTime = false;
- if (mEndTimePickerDialog == null) {
- mEndTimePickerDialog = TimePickerDialog.newInstance(new TimeListener(v),
- mTime.hour, mTime.minute, DateFormat.is24HourFormat(mActivity));
- } else {
- mEndTimePickerDialog.setStartTime(mTime.hour, mTime.minute);
- }
- dialog = mEndTimePickerDialog;
-
- }
-
- final FragmentManager fm = mActivity.getFragmentManager();
- fm.executePendingTransactions();
-
- if (dialog != null && !dialog.isAdded()) {
- dialog.show(fm, FRAG_TAG_TIME_PICKER);
- }
- }
- }
-
- private class DateListener implements OnDateSetListener {
- View mView;
-
- public DateListener(View view) {
- mView = view;
- }
-
- @Override
- public void onDateSet(DatePickerDialog view, int year, int month, int monthDay) {
- Log.d(TAG, "onDateSet: " + year + " " + month + " " + monthDay);
- // Cache the member variables locally to avoid inner class overhead.
- Time startTime = mStartTime;
- Time endTime = mEndTime;
-
- // Cache the start and end millis so that we limit the number
- // of calls to normalize() and toMillis(), which are fairly
- // expensive.
- long startMillis;
- long endMillis;
- if (mView == mStartDateButton) {
- // The start date was changed.
- int yearDuration = endTime.year - startTime.year;
- int monthDuration = endTime.month - startTime.month;
- int monthDayDuration = endTime.monthDay - startTime.monthDay;
-
- startTime.year = year;
- startTime.month = month;
- startTime.monthDay = monthDay;
- startMillis = startTime.normalize(true);
-
- // Also update the end date to keep the duration constant.
- endTime.year = year + yearDuration;
- endTime.month = month + monthDuration;
- endTime.monthDay = monthDay + monthDayDuration;
- endMillis = endTime.normalize(true);
-
- // If the start date has changed then update the repeats.
- populateRepeats();
-
- // Update tz in case the start time switched from/to DLS
- populateTimezone(startMillis);
- } else {
- // The end date was changed.
- startMillis = startTime.toMillis(true);
- endTime.year = year;
- endTime.month = month;
- endTime.monthDay = monthDay;
- endMillis = endTime.normalize(true);
-
- // Do not allow an event to have an end time before the start
- // time.
- if (endTime.before(startTime)) {
- endTime.set(startTime);
- endMillis = startMillis;
- }
- // Call populateTimezone if we support end time zone as well
- }
-
- setDate(mStartDateButton, startMillis);
- setDate(mEndDateButton, endMillis);
- setTime(mEndTimeButton, endMillis); // In case end time had to be
- // reset
- updateHomeTime();
- }
- }
-
- // Fills in the date and time fields
- private void populateWhen() {
- long startMillis = mStartTime.toMillis(false /* use isDst */);
- long endMillis = mEndTime.toMillis(false /* use isDst */);
- setDate(mStartDateButton, startMillis);
- setDate(mEndDateButton, endMillis);
-
- setTime(mStartTimeButton, startMillis);
- setTime(mEndTimeButton, endMillis);
-
- mStartDateButton.setOnClickListener(new DateClickListener(mStartTime));
- mEndDateButton.setOnClickListener(new DateClickListener(mEndTime));
-
- mStartTimeButton.setOnClickListener(new TimeClickListener(mStartTime));
- mEndTimeButton.setOnClickListener(new TimeClickListener(mEndTime));
- }
-
- // Implements OnTimeZoneSetListener
- @Override
- public void onTimeZoneSet(TimeZoneInfo tzi) {
- setTimezone(tzi.mTzId);
- updateHomeTime();
- }
-
- private void setTimezone(String timeZone) {
- mTimezone = timeZone;
- mStartTime.timezone = mTimezone;
- long timeMillis = mStartTime.normalize(true);
- mEndTime.timezone = mTimezone;
- mEndTime.normalize(true);
-
- populateTimezone(timeMillis);
- }
-
- private void populateTimezone(long eventStartTime) {
- if (mTzPickerUtils == null) {
- mTzPickerUtils = new TimeZonePickerUtils(mActivity);
- }
- CharSequence displayName =
- mTzPickerUtils.getGmtDisplayName(mActivity, mTimezone, eventStartTime, true);
-
- mTimezoneTextView.setText(displayName);
- mTimezoneButton.setText(displayName);
- }
-
- private void showTimezoneDialog() {
- Bundle b = new Bundle();
- b.putLong(TimeZonePickerDialog.BUNDLE_START_TIME_MILLIS, mStartTime.toMillis(false));
- b.putString(TimeZonePickerDialog.BUNDLE_TIME_ZONE, mTimezone);
-
- FragmentManager fm = mActivity.getFragmentManager();
- TimeZonePickerDialog tzpd = (TimeZonePickerDialog) fm
- .findFragmentByTag(FRAG_TAG_TIME_ZONE_PICKER);
- if (tzpd != null) {
- tzpd.dismiss();
- }
- tzpd = new TimeZonePickerDialog();
- tzpd.setArguments(b);
- tzpd.setOnTimeZoneSetListener(EditEventView.this);
- tzpd.show(fm, FRAG_TAG_TIME_ZONE_PICKER);
- }
-
- private void populateRepeats() {
- Resources r = mActivity.getResources();
- String repeatString;
- boolean enabled;
- if (!TextUtils.isEmpty(mRrule)) {
- repeatString = EventRecurrenceFormatter.getRepeatString(mActivity, r,
- mEventRecurrence, true);
-
- if (repeatString == null) {
- repeatString = r.getString(R.string.custom);
- Log.e(TAG, "Can't generate display string for " + mRrule);
- enabled = false;
- } else {
- // TODO Should give option to clear/reset rrule
- enabled = RecurrencePickerDialog.canHandleRecurrenceRule(mEventRecurrence);
- if (!enabled) {
- Log.e(TAG, "UI can't handle " + mRrule);
- }
- }
- } else {
- repeatString = r.getString(R.string.does_not_repeat);
- enabled = true;
- }
-
- mRruleButton.setText(repeatString);
-
- // Don't allow the user to make exceptions recurring events.
- if (mModel.mOriginalSyncId != null) {
- enabled = false;
- }
- mRruleButton.setOnClickListener(this);
- mRruleButton.setEnabled(enabled);
- }
-
- private class DateClickListener implements View.OnClickListener {
- private Time mTime;
-
- public DateClickListener(Time time) {
- mTime = time;
- }
-
- @Override
- public void onClick(View v) {
- if (!mView.hasWindowFocus()) {
- // Don't do anything if the activity if paused. Since Activity doesn't
- // have a built in way to do this, we would have to implement one ourselves and
- // either cast our Activity to a specialized activity base class or implement some
- // generic interface that tells us if an activity is paused. hasWindowFocus() is
- // close enough if not quite perfect.
- return;
- }
- if (v == mStartDateButton) {
- mDateSelectedWasStartDate = true;
- } else {
- mDateSelectedWasStartDate = false;
- }
-
- final DateListener listener = new DateListener(v);
- if (mDatePickerDialog != null) {
- mDatePickerDialog.dismiss();
- }
- mDatePickerDialog = DatePickerDialog.newInstance(listener,
- mTime.year, mTime.month, mTime.monthDay);
- mDatePickerDialog.setFirstDayOfWeek(Utils.getFirstDayOfWeekAsCalendar(mActivity));
- mDatePickerDialog.setYearRange(Utils.YEAR_MIN, Utils.YEAR_MAX);
- mDatePickerDialog.show(mActivity.getFragmentManager(), FRAG_TAG_DATE_PICKER);
- }
- }
-
- public static class CalendarsAdapter extends ResourceCursorAdapter {
- public CalendarsAdapter(Context context, int resourceId, Cursor c) {
- super(context, resourceId, c);
- setDropDownViewResource(R.layout.calendars_dropdown_item);
- }
-
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- View colorBar = view.findViewById(R.id.color);
- int colorColumn = cursor.getColumnIndexOrThrow(Calendars.CALENDAR_COLOR);
- int nameColumn = cursor.getColumnIndexOrThrow(Calendars.CALENDAR_DISPLAY_NAME);
- int ownerColumn = cursor.getColumnIndexOrThrow(Calendars.OWNER_ACCOUNT);
- if (colorBar != null) {
- colorBar.setBackgroundColor(Utils.getDisplayColorFromColor(cursor
- .getInt(colorColumn)));
- }
-
- TextView name = (TextView) view.findViewById(R.id.calendar_name);
- if (name != null) {
- String displayName = cursor.getString(nameColumn);
- name.setText(displayName);
-
- TextView accountName = (TextView) view.findViewById(R.id.account_name);
- if (accountName != null) {
- accountName.setText(cursor.getString(ownerColumn));
- accountName.setVisibility(TextView.VISIBLE);
- }
- }
- }
- }
-
- /**
- * Does prep steps for saving a calendar event.
- *
- * This triggers a parse of the attendees list and checks if the event is
- * ready to be saved. An event is ready to be saved so long as a model
- * exists and has a calendar it can be associated with, either because it's
- * an existing event or we've finished querying.
- *
- * @return false if there is no model or no calendar had been loaded yet,
- * true otherwise.
- */
- public boolean prepareForSave() {
- if (mModel == null || (mCalendarsCursor == null && mModel.mUri == null)) {
- return false;
- }
- return fillModelFromUI();
- }
-
- public boolean fillModelFromReadOnlyUi() {
- if (mModel == null || (mCalendarsCursor == null && mModel.mUri == null)) {
- return false;
- }
- mModel.mReminders = EventViewUtils.reminderItemsToReminders(
- mReminderItems, mReminderMinuteValues, mReminderMethodValues);
- mModel.mReminders.addAll(mUnsupportedReminders);
- mModel.normalizeReminders();
- int status = EventInfoFragment.getResponseFromButtonId(
- mResponseRadioGroup.getCheckedRadioButtonId());
- if (status != Attendees.ATTENDEE_STATUS_NONE) {
- mModel.mSelfAttendeeStatus = status;
- }
- return true;
- }
-
- // This is called if the user clicks on one of the buttons: "Save",
- // "Discard", or "Delete". This is also called if the user clicks
- // on the "remove reminder" button.
- @Override
- public void onClick(View view) {
- if (view == mRruleButton) {
- Bundle b = new Bundle();
- b.putLong(RecurrencePickerDialog.BUNDLE_START_TIME_MILLIS,
- mStartTime.toMillis(false));
- b.putString(RecurrencePickerDialog.BUNDLE_TIME_ZONE, mStartTime.timezone);
-
- // TODO may be more efficient to serialize and pass in EventRecurrence
- b.putString(RecurrencePickerDialog.BUNDLE_RRULE, mRrule);
-
- FragmentManager fm = mActivity.getFragmentManager();
- RecurrencePickerDialog rpd = (RecurrencePickerDialog) fm
- .findFragmentByTag(FRAG_TAG_RECUR_PICKER);
- if (rpd != null) {
- rpd.dismiss();
- }
- rpd = new RecurrencePickerDialog();
- rpd.setArguments(b);
- rpd.setOnRecurrenceSetListener(EditEventView.this);
- rpd.show(fm, FRAG_TAG_RECUR_PICKER);
- return;
- }
-
- // This must be a click on one of the "remove reminder" buttons
- LinearLayout reminderItem = (LinearLayout) view.getParent();
- LinearLayout parent = (LinearLayout) reminderItem.getParent();
- parent.removeView(reminderItem);
- mReminderItems.remove(reminderItem);
- updateRemindersVisibility(mReminderItems.size());
- EventViewUtils.updateAddReminderButton(mView, mReminderItems, mModel.mCalendarMaxReminders);
- }
-
- @Override
- public void onRecurrenceSet(String rrule) {
- Log.d(TAG, "Old rrule:" + mRrule);
- Log.d(TAG, "New rrule:" + rrule);
- mRrule = rrule;
- if (mRrule != null) {
- mEventRecurrence.parse(mRrule);
- }
- populateRepeats();
- }
-
- // This is called if the user cancels the "No calendars" dialog.
- // The "No calendars" dialog is shown if there are no syncable calendars.
- @Override
- public void onCancel(DialogInterface dialog) {
- if (dialog == mLoadingCalendarsDialog) {
- mLoadingCalendarsDialog = null;
- mSaveAfterQueryComplete = false;
- } else if (dialog == mNoCalendarsDialog) {
- mDone.setDoneCode(Utils.DONE_REVERT);
- mDone.run();
- return;
- }
- }
-
- // This is called if the user clicks on a dialog button.
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (dialog == mNoCalendarsDialog) {
- mDone.setDoneCode(Utils.DONE_REVERT);
- mDone.run();
- if (which == DialogInterface.BUTTON_POSITIVE) {
- Intent nextIntent = new Intent(Settings.ACTION_ADD_ACCOUNT);
- final String[] array = {"com.android.calendar"};
- nextIntent.putExtra(Settings.EXTRA_AUTHORITIES, array);
- nextIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
- mActivity.startActivity(nextIntent);
- }
- }
- }
-
- // Goes through the UI elements and updates the model as necessary
- private boolean fillModelFromUI() {
- if (mModel == null) {
- return false;
- }
- mModel.mReminders = EventViewUtils.reminderItemsToReminders(mReminderItems,
- mReminderMinuteValues, mReminderMethodValues);
- mModel.mReminders.addAll(mUnsupportedReminders);
- mModel.normalizeReminders();
- mModel.mHasAlarm = mReminderItems.size() > 0;
- mModel.mTitle = mTitleTextView.getText().toString();
- mModel.mAllDay = mAllDayCheckBox.isChecked();
- mModel.mLocation = mLocationTextView.getText().toString();
- mModel.mDescription = mDescriptionTextView.getText().toString();
- if (TextUtils.isEmpty(mModel.mLocation)) {
- mModel.mLocation = null;
- }
- if (TextUtils.isEmpty(mModel.mDescription)) {
- mModel.mDescription = null;
- }
-
- int status = EventInfoFragment.getResponseFromButtonId(mResponseRadioGroup
- .getCheckedRadioButtonId());
- if (status != Attendees.ATTENDEE_STATUS_NONE) {
- mModel.mSelfAttendeeStatus = status;
- }
-
- if (mAttendeesList != null) {
- mEmailValidator.setRemoveInvalid(true);
- mAttendeesList.performValidation();
- mModel.mAttendeesList.clear();
- mModel.addAttendees(mAttendeesList.getText().toString(), mEmailValidator);
- mEmailValidator.setRemoveInvalid(false);
- }
-
- // If this was a new event we need to fill in the Calendar information
- if (mModel.mUri == null) {
- mModel.mCalendarId = mCalendarsSpinner.getSelectedItemId();
- int calendarCursorPosition = mCalendarsSpinner.getSelectedItemPosition();
- if (mCalendarsCursor.moveToPosition(calendarCursorPosition)) {
- String defaultCalendar = mCalendarsCursor.getString(
- EditEventHelper.CALENDARS_INDEX_OWNER_ACCOUNT);
- Utils.setSharedPreference(
- mActivity, GeneralPreferences.KEY_DEFAULT_CALENDAR, defaultCalendar);
- mModel.mOwnerAccount = defaultCalendar;
- mModel.mOrganizer = defaultCalendar;
- mModel.mCalendarId = mCalendarsCursor.getLong(EditEventHelper.CALENDARS_INDEX_ID);
- }
- }
-
- if (mModel.mAllDay) {
- // Reset start and end time, increment the monthDay by 1, and set
- // the timezone to UTC, as required for all-day events.
- mTimezone = Time.TIMEZONE_UTC;
- mStartTime.hour = 0;
- mStartTime.minute = 0;
- mStartTime.second = 0;
- mStartTime.timezone = mTimezone;
- mModel.mStart = mStartTime.normalize(true);
-
- mEndTime.hour = 0;
- mEndTime.minute = 0;
- mEndTime.second = 0;
- mEndTime.timezone = mTimezone;
- // When a user see the event duration as "X - Y" (e.g. Oct. 28 - Oct. 29), end time
- // should be Y + 1 (Oct.30).
- final long normalizedEndTimeMillis =
- mEndTime.normalize(true) + DateUtils.DAY_IN_MILLIS;
- if (normalizedEndTimeMillis < mModel.mStart) {
- // mEnd should be midnight of the next day of mStart.
- mModel.mEnd = mModel.mStart + DateUtils.DAY_IN_MILLIS;
- } else {
- mModel.mEnd = normalizedEndTimeMillis;
- }
- } else {
- mStartTime.timezone = mTimezone;
- mEndTime.timezone = mTimezone;
- mModel.mStart = mStartTime.toMillis(true);
- mModel.mEnd = mEndTime.toMillis(true);
- }
- mModel.mTimezone = mTimezone;
- mModel.mAccessLevel = mAccessLevelSpinner.getSelectedItemPosition();
- // TODO set correct availability value
- mModel.mAvailability = mAvailabilityValues.get(mAvailabilitySpinner
- .getSelectedItemPosition());
-
- // rrrule
- // If we're making an exception we don't want it to be a repeating
- // event.
- if (mModification == EditEventHelper.MODIFY_SELECTED) {
- mModel.mRrule = null;
- } else {
- mModel.mRrule = mRrule;
- }
-
- return true;
- }
-
- public EditEventView(Activity activity, View view, EditDoneRunnable done,
- boolean timeSelectedWasStartTime, boolean dateSelectedWasStartDate) {
-
- mActivity = activity;
- mView = view;
- mDone = done;
-
- // cache top level view elements
- mLoadingMessage = (TextView) view.findViewById(R.id.loading_message);
- mScrollView = (ScrollView) view.findViewById(R.id.scroll_view);
-
- // cache all the widgets
- mCalendarsSpinner = (Spinner) view.findViewById(R.id.calendars_spinner);
- mTitleTextView = (TextView) view.findViewById(R.id.title);
- mLocationTextView = (AutoCompleteTextView) view.findViewById(R.id.location);
- mDescriptionTextView = (TextView) view.findViewById(R.id.description);
- mTimezoneLabel = (TextView) view.findViewById(R.id.timezone_label);
- mStartDateButton = (Button) view.findViewById(R.id.start_date);
- mEndDateButton = (Button) view.findViewById(R.id.end_date);
- mWhenView = (TextView) mView.findViewById(R.id.when);
- mTimezoneTextView = (TextView) mView.findViewById(R.id.timezone_textView);
- mStartTimeButton = (Button) view.findViewById(R.id.start_time);
- mEndTimeButton = (Button) view.findViewById(R.id.end_time);
- mTimezoneButton = (Button) view.findViewById(R.id.timezone_button);
- mTimezoneButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- showTimezoneDialog();
- }
- });
- mTimezoneRow = view.findViewById(R.id.timezone_button_row);
- mStartTimeHome = (TextView) view.findViewById(R.id.start_time_home_tz);
- mStartDateHome = (TextView) view.findViewById(R.id.start_date_home_tz);
- mEndTimeHome = (TextView) view.findViewById(R.id.end_time_home_tz);
- mEndDateHome = (TextView) view.findViewById(R.id.end_date_home_tz);
- mAllDayCheckBox = (CheckBox) view.findViewById(R.id.is_all_day);
- mRruleButton = (Button) view.findViewById(R.id.rrule);
- mAvailabilitySpinner = (Spinner) view.findViewById(R.id.availability);
- mAccessLevelSpinner = (Spinner) view.findViewById(R.id.visibility);
- mCalendarSelectorGroup = view.findViewById(R.id.calendar_selector_group);
- mCalendarSelectorWrapper = view.findViewById(R.id.calendar_selector_wrapper);
- mCalendarStaticGroup = view.findViewById(R.id.calendar_group);
- mRemindersGroup = view.findViewById(R.id.reminders_row);
- mResponseGroup = view.findViewById(R.id.response_row);
- mOrganizerGroup = view.findViewById(R.id.organizer_row);
- mAttendeesGroup = view.findViewById(R.id.add_attendees_row);
- mLocationGroup = view.findViewById(R.id.where_row);
- mDescriptionGroup = view.findViewById(R.id.description_row);
- mStartHomeGroup = view.findViewById(R.id.from_row_home_tz);
- mEndHomeGroup = view.findViewById(R.id.to_row_home_tz);
- mAttendeesList = (MultiAutoCompleteTextView) view.findViewById(R.id.attendees);
-
- mColorPickerNewEvent = view.findViewById(R.id.change_color_new_event);
- mColorPickerExistingEvent = view.findViewById(R.id.change_color_existing_event);
-
- mTitleTextView.setTag(mTitleTextView.getBackground());
- mLocationTextView.setTag(mLocationTextView.getBackground());
- mLocationAdapter = new EventLocationAdapter(activity);
- mLocationTextView.setAdapter(mLocationAdapter);
- mLocationTextView.setOnEditorActionListener(new OnEditorActionListener() {
- @Override
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- if (actionId == EditorInfo.IME_ACTION_DONE) {
- // Dismiss the suggestions dropdown. Return false so the other
- // side effects still occur (soft keyboard going away, etc.).
- mLocationTextView.dismissDropDown();
- }
- return false;
- }
- });
-
- mAvailabilityExplicitlySet = false;
- mAllDayChangingAvailability = false;
- mAvailabilityCurrentlySelected = -1;
- mAvailabilitySpinner.setOnItemSelectedListener(
- new OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent,
- View view, int position, long id) {
- // The spinner's onItemSelected gets called while it is being
- // initialized to the first item, and when we explicitly set it
- // in the allDay checkbox toggling, so we need these checks to
- // find out when the spinner is actually being clicked.
-
- // Set the initial selection.
- if (mAvailabilityCurrentlySelected == -1) {
- mAvailabilityCurrentlySelected = position;
- }
-
- if (mAvailabilityCurrentlySelected != position &&
- !mAllDayChangingAvailability) {
- mAvailabilityExplicitlySet = true;
- } else {
- mAvailabilityCurrentlySelected = position;
- mAllDayChangingAvailability = false;
- }
- }
- @Override
- public void onNothingSelected(AdapterView<?> arg0) { }
- });
-
-
- mDescriptionTextView.setTag(mDescriptionTextView.getBackground());
- mAttendeesList.setTag(mAttendeesList.getBackground());
- mOriginalPadding[0] = mLocationTextView.getPaddingLeft();
- mOriginalPadding[1] = mLocationTextView.getPaddingTop();
- mOriginalPadding[2] = mLocationTextView.getPaddingRight();
- mOriginalPadding[3] = mLocationTextView.getPaddingBottom();
- mEditViewList.add(mTitleTextView);
- mEditViewList.add(mLocationTextView);
- mEditViewList.add(mDescriptionTextView);
- mEditViewList.add(mAttendeesList);
-
- mViewOnlyList.add(view.findViewById(R.id.when_row));
- mViewOnlyList.add(view.findViewById(R.id.timezone_textview_row));
-
- mEditOnlyList.add(view.findViewById(R.id.all_day_row));
- mEditOnlyList.add(view.findViewById(R.id.availability_row));
- mEditOnlyList.add(view.findViewById(R.id.visibility_row));
- mEditOnlyList.add(view.findViewById(R.id.from_row));
- mEditOnlyList.add(view.findViewById(R.id.to_row));
- mEditOnlyList.add(mTimezoneRow);
- mEditOnlyList.add(mStartHomeGroup);
- mEditOnlyList.add(mEndHomeGroup);
-
- mResponseRadioGroup = (RadioGroup) view.findViewById(R.id.response_value);
- mRemindersContainer = (LinearLayout) view.findViewById(R.id.reminder_items_container);
-
- mTimezone = Utils.getTimeZone(activity, null);
- mIsMultipane = activity.getResources().getBoolean(R.bool.tablet_config);
- mStartTime = new Time(mTimezone);
- mEndTime = new Time(mTimezone);
- mEmailValidator = new Rfc822Validator(null);
- initMultiAutoCompleteTextView((RecipientEditTextView) mAttendeesList);
-
- // Display loading screen
- setModel(null);
-
- FragmentManager fm = activity.getFragmentManager();
- RecurrencePickerDialog rpd = (RecurrencePickerDialog) fm
- .findFragmentByTag(FRAG_TAG_RECUR_PICKER);
- if (rpd != null) {
- rpd.setOnRecurrenceSetListener(this);
- }
- TimeZonePickerDialog tzpd = (TimeZonePickerDialog) fm
- .findFragmentByTag(FRAG_TAG_TIME_ZONE_PICKER);
- if (tzpd != null) {
- tzpd.setOnTimeZoneSetListener(this);
- }
- TimePickerDialog tpd = (TimePickerDialog) fm.findFragmentByTag(FRAG_TAG_TIME_PICKER);
- if (tpd != null) {
- View v;
- mTimeSelectedWasStartTime = timeSelectedWasStartTime;
- if (timeSelectedWasStartTime) {
- v = mStartTimeButton;
- } else {
- v = mEndTimeButton;
- }
- tpd.setOnTimeSetListener(new TimeListener(v));
- }
- mDatePickerDialog = (DatePickerDialog) fm.findFragmentByTag(FRAG_TAG_DATE_PICKER);
- if (mDatePickerDialog != null) {
- View v;
- mDateSelectedWasStartDate = dateSelectedWasStartDate;
- if (dateSelectedWasStartDate) {
- v = mStartDateButton;
- } else {
- v = mEndDateButton;
- }
- mDatePickerDialog.setOnDateSetListener(new DateListener(v));
- }
- }
-
-
- /**
- * Loads an integer array asset into a list.
- */
- private static ArrayList<Integer> loadIntegerArray(Resources r, int resNum) {
- int[] vals = r.getIntArray(resNum);
- int size = vals.length;
- ArrayList<Integer> list = new ArrayList<Integer>(size);
-
- for (int i = 0; i < size; i++) {
- list.add(vals[i]);
- }
-
- return list;
- }
-
- /**
- * Loads a String array asset into a list.
- */
- private static ArrayList<String> loadStringArray(Resources r, int resNum) {
- String[] labels = r.getStringArray(resNum);
- ArrayList<String> list = new ArrayList<String>(Arrays.asList(labels));
- return list;
- }
-
- private void prepareAvailability() {
- Resources r = mActivity.getResources();
-
- mAvailabilityValues = loadIntegerArray(r, R.array.availability_values);
- mAvailabilityLabels = loadStringArray(r, R.array.availability);
- // Copy the unadulterated availability labels for all-day toggling.
- mOriginalAvailabilityLabels = new ArrayList<String>();
- mOriginalAvailabilityLabels.addAll(mAvailabilityLabels);
-
- if (mModel.mCalendarAllowedAvailability != null) {
- EventViewUtils.reduceMethodList(mAvailabilityValues, mAvailabilityLabels,
- mModel.mCalendarAllowedAvailability);
- }
-
- mAvailabilityAdapter = new ArrayAdapter<String>(mActivity,
- android.R.layout.simple_spinner_item, mAvailabilityLabels);
- mAvailabilityAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- mAvailabilitySpinner.setAdapter(mAvailabilityAdapter);
- }
-
- /**
- * Prepares the reminder UI elements.
- * <p>
- * (Re-)loads the minutes / methods lists from the XML assets, adds/removes items as
- * needed for the current set of reminders and calendar properties, and then creates UI
- * elements.
- */
- private void prepareReminders() {
- CalendarEventModel model = mModel;
- Resources r = mActivity.getResources();
-
- // Load the labels and corresponding numeric values for the minutes and methods lists
- // from the assets. If we're switching calendars, we need to clear and re-populate the
- // lists (which may have elements added and removed based on calendar properties). This
- // is mostly relevant for "methods", since we shouldn't have any "minutes" values in a
- // new event that aren't in the default set.
- mReminderMinuteValues = loadIntegerArray(r, R.array.reminder_minutes_values);
- mReminderMinuteLabels = loadStringArray(r, R.array.reminder_minutes_labels);
- mReminderMethodValues = loadIntegerArray(r, R.array.reminder_methods_values);
- mReminderMethodLabels = loadStringArray(r, R.array.reminder_methods_labels);
-
- // Remove any reminder methods that aren't allowed for this calendar. If this is
- // a new event, mCalendarAllowedReminders may not be set the first time we're called.
- if (mModel.mCalendarAllowedReminders != null) {
- EventViewUtils.reduceMethodList(mReminderMethodValues, mReminderMethodLabels,
- mModel.mCalendarAllowedReminders);
- }
-
- int numReminders = 0;
- if (model.mHasAlarm) {
- ArrayList<ReminderEntry> reminders = model.mReminders;
- numReminders = reminders.size();
- // Insert any minute values that aren't represented in the minutes list.
- for (ReminderEntry re : reminders) {
- if (mReminderMethodValues.contains(re.getMethod())) {
- EventViewUtils.addMinutesToList(mActivity, mReminderMinuteValues,
- mReminderMinuteLabels, re.getMinutes());
- }
- }
-
- // Create a UI element for each reminder. We display all of the reminders we get
- // from the provider, even if the count exceeds the calendar maximum. (Also, for
- // a new event, we won't have a maxReminders value available.)
- mUnsupportedReminders.clear();
- for (ReminderEntry re : reminders) {
- if (mReminderMethodValues.contains(re.getMethod())
- || re.getMethod() == Reminders.METHOD_DEFAULT) {
- EventViewUtils.addReminder(mActivity, mScrollView, this, mReminderItems,
- mReminderMinuteValues, mReminderMinuteLabels, mReminderMethodValues,
- mReminderMethodLabels, re, Integer.MAX_VALUE, null);
- } else {
- // TODO figure out a way to display unsupported reminders
- mUnsupportedReminders.add(re);
- }
- }
- }
-
- updateRemindersVisibility(numReminders);
- EventViewUtils.updateAddReminderButton(mView, mReminderItems, mModel.mCalendarMaxReminders);
- }
-
- /**
- * Fill in the view with the contents of the given event model. This allows
- * an edit view to be initialized before the event has been loaded. Passing
- * in null for the model will display a loading screen. A non-null model
- * will fill in the view's fields with the data contained in the model.
- *
- * @param model The event model to pull the data from
- */
- public void setModel(CalendarEventModel model) {
- mModel = model;
-
- // Need to close the autocomplete adapter to prevent leaking cursors.
- if (mAddressAdapter != null && mAddressAdapter instanceof EmailAddressAdapter) {
- ((EmailAddressAdapter)mAddressAdapter).close();
- mAddressAdapter = null;
- }
-
- if (model == null) {
- // Display loading screen
- mLoadingMessage.setVisibility(View.VISIBLE);
- mScrollView.setVisibility(View.GONE);
- return;
- }
-
- boolean canRespond = EditEventHelper.canRespond(model);
-
- long begin = model.mStart;
- long end = model.mEnd;
- mTimezone = model.mTimezone; // this will be UTC for all day events
-
- // Set up the starting times
- if (begin > 0) {
- mStartTime.timezone = mTimezone;
- mStartTime.set(begin);
- mStartTime.normalize(true);
- }
- if (end > 0) {
- mEndTime.timezone = mTimezone;
- mEndTime.set(end);
- mEndTime.normalize(true);
- }
-
- mRrule = model.mRrule;
- if (!TextUtils.isEmpty(mRrule)) {
- mEventRecurrence.parse(mRrule);
- }
-
- if (mEventRecurrence.startDate == null) {
- mEventRecurrence.startDate = mStartTime;
- }
-
- // If the user is allowed to change the attendees set up the view and
- // validator
- if (!model.mHasAttendeeData) {
- mAttendeesGroup.setVisibility(View.GONE);
- }
-
- mAllDayCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- setAllDayViewsVisibility(isChecked);
- }
- });
-
- boolean prevAllDay = mAllDayCheckBox.isChecked();
- mAllDay = false; // default to false. Let setAllDayViewsVisibility update it as needed
- if (model.mAllDay) {
- mAllDayCheckBox.setChecked(true);
- // put things back in local time for all day events
- mTimezone = Utils.getTimeZone(mActivity, null);
- mStartTime.timezone = mTimezone;
- mEndTime.timezone = mTimezone;
- mEndTime.normalize(true);
- } else {
- mAllDayCheckBox.setChecked(false);
- }
- // On a rotation we need to update the views but onCheckedChanged
- // doesn't get called
- if (prevAllDay == mAllDayCheckBox.isChecked()) {
- setAllDayViewsVisibility(prevAllDay);
- }
-
- populateTimezone(mStartTime.normalize(true));
-
- SharedPreferences prefs = GeneralPreferences.getSharedPreferences(mActivity);
- String defaultReminderString = prefs.getString(
- GeneralPreferences.KEY_DEFAULT_REMINDER, GeneralPreferences.NO_REMINDER_STRING);
- mDefaultReminderMinutes = Integer.parseInt(defaultReminderString);
-
- prepareReminders();
- prepareAvailability();
-
- View reminderAddButton = mView.findViewById(R.id.reminder_add);
- View.OnClickListener addReminderOnClickListener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- addReminder();
- }
- };
- reminderAddButton.setOnClickListener(addReminderOnClickListener);
-
- if (!mIsMultipane) {
- mView.findViewById(R.id.is_all_day_label).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mAllDayCheckBox.setChecked(!mAllDayCheckBox.isChecked());
- }
- });
- }
-
- if (model.mTitle != null) {
- mTitleTextView.setTextKeepState(model.mTitle);
- }
-
- if (model.mIsOrganizer || TextUtils.isEmpty(model.mOrganizer)
- || model.mOrganizer.endsWith(GOOGLE_SECONDARY_CALENDAR)) {
- mView.findViewById(R.id.organizer_label).setVisibility(View.GONE);
- mView.findViewById(R.id.organizer).setVisibility(View.GONE);
- mOrganizerGroup.setVisibility(View.GONE);
- } else {
- ((TextView) mView.findViewById(R.id.organizer)).setText(model.mOrganizerDisplayName);
- }
-
- if (model.mLocation != null) {
- mLocationTextView.setTextKeepState(model.mLocation);
- }
-
- if (model.mDescription != null) {
- mDescriptionTextView.setTextKeepState(model.mDescription);
- }
-
- int availIndex = mAvailabilityValues.indexOf(model.mAvailability);
- if (availIndex != -1) {
- mAvailabilitySpinner.setSelection(availIndex);
- }
- mAccessLevelSpinner.setSelection(model.mAccessLevel);
-
- View responseLabel = mView.findViewById(R.id.response_label);
- if (canRespond) {
- int buttonToCheck = EventInfoFragment
- .findButtonIdForResponse(model.mSelfAttendeeStatus);
- mResponseRadioGroup.check(buttonToCheck); // -1 clear all radio buttons
- mResponseRadioGroup.setVisibility(View.VISIBLE);
- responseLabel.setVisibility(View.VISIBLE);
- } else {
- responseLabel.setVisibility(View.GONE);
- mResponseRadioGroup.setVisibility(View.GONE);
- mResponseGroup.setVisibility(View.GONE);
- }
-
- if (model.mUri != null) {
- // This is an existing event so hide the calendar spinner
- // since we can't change the calendar.
- View calendarGroup = mView.findViewById(R.id.calendar_selector_group);
- calendarGroup.setVisibility(View.GONE);
- TextView tv = (TextView) mView.findViewById(R.id.calendar_textview);
- tv.setText(model.mCalendarDisplayName);
- tv = (TextView) mView.findViewById(R.id.calendar_textview_secondary);
- if (tv != null) {
- tv.setText(model.mOwnerAccount);
- }
- } else {
- View calendarGroup = mView.findViewById(R.id.calendar_group);
- calendarGroup.setVisibility(View.GONE);
- }
- if (model.isEventColorInitialized()) {
- updateHeadlineColor(model, model.getEventColor());
- }
-
- populateWhen();
- populateRepeats();
- updateAttendees(model.mAttendeesList);
-
- updateView();
- mScrollView.setVisibility(View.VISIBLE);
- mLoadingMessage.setVisibility(View.GONE);
- sendAccessibilityEvent();
- }
-
- public void updateHeadlineColor(CalendarEventModel model, int displayColor) {
- if (model.mUri != null) {
- if (mIsMultipane) {
- mView.findViewById(R.id.calendar_textview_with_colorpicker)
- .setBackgroundColor(displayColor);
- } else {
- mView.findViewById(R.id.calendar_group).setBackgroundColor(displayColor);
- }
- } else {
- setSpinnerBackgroundColor(displayColor);
- }
- }
-
- private void setSpinnerBackgroundColor(int displayColor) {
- if (mIsMultipane) {
- mCalendarSelectorWrapper.setBackgroundColor(displayColor);
- } else {
- mCalendarSelectorGroup.setBackgroundColor(displayColor);
- }
- }
-
- private void sendAccessibilityEvent() {
- AccessibilityManager am =
- (AccessibilityManager) mActivity.getSystemService(Service.ACCESSIBILITY_SERVICE);
- if (!am.isEnabled() || mModel == null) {
- return;
- }
- StringBuilder b = new StringBuilder();
- addFieldsRecursive(b, mView);
- CharSequence msg = b.toString();
-
- AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_FOCUSED);
- event.setClassName(getClass().getName());
- event.setPackageName(mActivity.getPackageName());
- event.getText().add(msg);
- event.setAddedCount(msg.length());
-
- am.sendAccessibilityEvent(event);
- }
-
- private void addFieldsRecursive(StringBuilder b, View v) {
- if (v == null || v.getVisibility() != View.VISIBLE) {
- return;
- }
- if (v instanceof TextView) {
- CharSequence tv = ((TextView) v).getText();
- if (!TextUtils.isEmpty(tv.toString().trim())) {
- b.append(tv + PERIOD_SPACE);
- }
- } else if (v instanceof RadioGroup) {
- RadioGroup rg = (RadioGroup) v;
- int id = rg.getCheckedRadioButtonId();
- if (id != View.NO_ID) {
- b.append(((RadioButton) (v.findViewById(id))).getText() + PERIOD_SPACE);
- }
- } else if (v instanceof Spinner) {
- Spinner s = (Spinner) v;
- if (s.getSelectedItem() instanceof String) {
- String str = ((String) (s.getSelectedItem())).trim();
- if (!TextUtils.isEmpty(str)) {
- b.append(str + PERIOD_SPACE);
- }
- }
- } else if (v instanceof ViewGroup) {
- ViewGroup vg = (ViewGroup) v;
- int children = vg.getChildCount();
- for (int i = 0; i < children; i++) {
- addFieldsRecursive(b, vg.getChildAt(i));
- }
- }
- }
-
- /**
- * Creates a single line string for the time/duration
- */
- protected void setWhenString() {
- String when;
- int flags = DateUtils.FORMAT_SHOW_DATE;
- String tz = mTimezone;
- if (mModel.mAllDay) {
- flags |= DateUtils.FORMAT_SHOW_WEEKDAY;
- tz = Time.TIMEZONE_UTC;
- } else {
- flags |= DateUtils.FORMAT_SHOW_TIME;
- if (DateFormat.is24HourFormat(mActivity)) {
- flags |= DateUtils.FORMAT_24HOUR;
- }
- }
- long startMillis = mStartTime.normalize(true);
- long endMillis = mEndTime.normalize(true);
- mSB.setLength(0);
- when = DateUtils
- .formatDateRange(mActivity, mF, startMillis, endMillis, flags, tz).toString();
- mWhenView.setText(when);
- }
-
- /**
- * Configures the Calendars spinner. This is only done for new events, because only new
- * events allow you to select a calendar while editing an event.
- * <p>
- * We tuck a reference to a Cursor with calendar database data into the spinner, so that
- * we can easily extract calendar-specific values when the value changes (the spinner's
- * onItemSelected callback is configured).
- */
- public void setCalendarsCursor(Cursor cursor, boolean userVisible, long selectedCalendarId) {
- // If there are no syncable calendars, then we cannot allow
- // creating a new event.
- mCalendarsCursor = cursor;
- if (cursor == null || cursor.getCount() == 0) {
- // Cancel the "loading calendars" dialog if it exists
- if (mSaveAfterQueryComplete) {
- mLoadingCalendarsDialog.cancel();
- }
- if (!userVisible) {
- return;
- }
- // Create an error message for the user that, when clicked,
- // will exit this activity without saving the event.
- AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
- builder.setTitle(R.string.no_syncable_calendars).setIconAttribute(
- android.R.attr.alertDialogIcon).setMessage(R.string.no_calendars_found)
- .setPositiveButton(R.string.add_account, this)
- .setNegativeButton(android.R.string.no, this).setOnCancelListener(this);
- mNoCalendarsDialog = builder.show();
- return;
- }
-
- int selection;
- if (selectedCalendarId != -1) {
- selection = findSelectedCalendarPosition(cursor, selectedCalendarId);
- } else {
- selection = findDefaultCalendarPosition(cursor);
- }
-
- // populate the calendars spinner
- CalendarsAdapter adapter = new CalendarsAdapter(mActivity,
- R.layout.calendars_spinner_item, cursor);
- mCalendarsSpinner.setAdapter(adapter);
- mCalendarsSpinner.setOnItemSelectedListener(this);
- mCalendarsSpinner.setSelection(selection);
-
- if (mSaveAfterQueryComplete) {
- mLoadingCalendarsDialog.cancel();
- if (prepareForSave() && fillModelFromUI()) {
- int exit = userVisible ? Utils.DONE_EXIT : 0;
- mDone.setDoneCode(Utils.DONE_SAVE | exit);
- mDone.run();
- } else if (userVisible) {
- mDone.setDoneCode(Utils.DONE_EXIT);
- mDone.run();
- } else if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "SetCalendarsCursor:Save failed and unable to exit view");
- }
- return;
- }
- }
-
- /**
- * Updates the view based on {@link #mModification} and {@link #mModel}
- */
- public void updateView() {
- if (mModel == null) {
- return;
- }
- if (EditEventHelper.canModifyEvent(mModel)) {
- setViewStates(mModification);
- } else {
- setViewStates(Utils.MODIFY_UNINITIALIZED);
- }
- }
-
- private void setViewStates(int mode) {
- // Extra canModify check just in case
- if (mode == Utils.MODIFY_UNINITIALIZED || !EditEventHelper.canModifyEvent(mModel)) {
- setWhenString();
-
- for (View v : mViewOnlyList) {
- v.setVisibility(View.VISIBLE);
- }
- for (View v : mEditOnlyList) {
- v.setVisibility(View.GONE);
- }
- for (View v : mEditViewList) {
- v.setEnabled(false);
- v.setBackgroundDrawable(null);
- }
- mCalendarSelectorGroup.setVisibility(View.GONE);
- mCalendarStaticGroup.setVisibility(View.VISIBLE);
- mRruleButton.setEnabled(false);
- if (EditEventHelper.canAddReminders(mModel)) {
- mRemindersGroup.setVisibility(View.VISIBLE);
- } else {
- mRemindersGroup.setVisibility(View.GONE);
- }
- if (TextUtils.isEmpty(mLocationTextView.getText())) {
- mLocationGroup.setVisibility(View.GONE);
- }
- if (TextUtils.isEmpty(mDescriptionTextView.getText())) {
- mDescriptionGroup.setVisibility(View.GONE);
- }
- } else {
- for (View v : mViewOnlyList) {
- v.setVisibility(View.GONE);
- }
- for (View v : mEditOnlyList) {
- v.setVisibility(View.VISIBLE);
- }
- for (View v : mEditViewList) {
- v.setEnabled(true);
- if (v.getTag() != null) {
- v.setBackgroundDrawable((Drawable) v.getTag());
- v.setPadding(mOriginalPadding[0], mOriginalPadding[1], mOriginalPadding[2],
- mOriginalPadding[3]);
- }
- }
- if (mModel.mUri == null) {
- mCalendarSelectorGroup.setVisibility(View.VISIBLE);
- mCalendarStaticGroup.setVisibility(View.GONE);
- } else {
- mCalendarSelectorGroup.setVisibility(View.GONE);
- mCalendarStaticGroup.setVisibility(View.VISIBLE);
- }
- if (mModel.mOriginalSyncId == null) {
- mRruleButton.setEnabled(true);
- } else {
- mRruleButton.setEnabled(false);
- mRruleButton.setBackgroundDrawable(null);
- }
- mRemindersGroup.setVisibility(View.VISIBLE);
-
- mLocationGroup.setVisibility(View.VISIBLE);
- mDescriptionGroup.setVisibility(View.VISIBLE);
- }
- setAllDayViewsVisibility(mAllDayCheckBox.isChecked());
- }
-
- public void setModification(int modifyWhich) {
- mModification = modifyWhich;
- updateView();
- updateHomeTime();
- }
-
- private int findSelectedCalendarPosition(Cursor calendarsCursor, long calendarId) {
- if (calendarsCursor.getCount() <= 0) {
- return -1;
- }
- int calendarIdColumn = calendarsCursor.getColumnIndexOrThrow(Calendars._ID);
- int position = 0;
- calendarsCursor.moveToPosition(-1);
- while (calendarsCursor.moveToNext()) {
- if (calendarsCursor.getLong(calendarIdColumn) == calendarId) {
- return position;
- }
- position++;
- }
- return 0;
- }
-
- // Find the calendar position in the cursor that matches calendar in
- // preference
- private int findDefaultCalendarPosition(Cursor calendarsCursor) {
- if (calendarsCursor.getCount() <= 0) {
- return -1;
- }
-
- String defaultCalendar = Utils.getSharedPreference(
- mActivity, GeneralPreferences.KEY_DEFAULT_CALENDAR, (String) null);
-
- int calendarsOwnerIndex = calendarsCursor.getColumnIndexOrThrow(Calendars.OWNER_ACCOUNT);
- int accountNameIndex = calendarsCursor.getColumnIndexOrThrow(Calendars.ACCOUNT_NAME);
- int accountTypeIndex = calendarsCursor.getColumnIndexOrThrow(Calendars.ACCOUNT_TYPE);
- int position = 0;
- calendarsCursor.moveToPosition(-1);
- while (calendarsCursor.moveToNext()) {
- String calendarOwner = calendarsCursor.getString(calendarsOwnerIndex);
- if (defaultCalendar == null) {
- // There is no stored default upon the first time running. Use a primary
- // calendar in this case.
- if (calendarOwner != null &&
- calendarOwner.equals(calendarsCursor.getString(accountNameIndex)) &&
- !CalendarContract.ACCOUNT_TYPE_LOCAL.equals(
- calendarsCursor.getString(accountTypeIndex))) {
- return position;
- }
- } else if (defaultCalendar.equals(calendarOwner)) {
- // Found the default calendar.
- return position;
- }
- position++;
- }
- return 0;
- }
-
- private void updateAttendees(HashMap<String, Attendee> attendeesList) {
- if (attendeesList == null || attendeesList.isEmpty()) {
- return;
- }
- mAttendeesList.setText(null);
- for (Attendee attendee : attendeesList.values()) {
-
- // TODO: Please remove separator when Calendar uses the chips MR2 project
-
- // Adding a comma separator between email addresses to prevent a chips MR1.1 bug
- // in which email addresses are concatenated together with no separator.
- mAttendeesList.append(attendee.mEmail + ", ");
- }
- }
-
- private void updateRemindersVisibility(int numReminders) {
- if (numReminders == 0) {
- mRemindersContainer.setVisibility(View.GONE);
- } else {
- mRemindersContainer.setVisibility(View.VISIBLE);
- }
- }
-
- /**
- * Add a new reminder when the user hits the "add reminder" button. We use the default
- * reminder time and method.
- */
- private void addReminder() {
- // TODO: when adding a new reminder, make it different from the
- // last one in the list (if any).
- if (mDefaultReminderMinutes == GeneralPreferences.NO_REMINDER) {
- EventViewUtils.addReminder(mActivity, mScrollView, this, mReminderItems,
- mReminderMinuteValues, mReminderMinuteLabels,
- mReminderMethodValues, mReminderMethodLabels,
- ReminderEntry.valueOf(GeneralPreferences.REMINDER_DEFAULT_TIME),
- mModel.mCalendarMaxReminders, null);
- } else {
- EventViewUtils.addReminder(mActivity, mScrollView, this, mReminderItems,
- mReminderMinuteValues, mReminderMinuteLabels,
- mReminderMethodValues, mReminderMethodLabels,
- ReminderEntry.valueOf(mDefaultReminderMinutes),
- mModel.mCalendarMaxReminders, null);
- }
- updateRemindersVisibility(mReminderItems.size());
- EventViewUtils.updateAddReminderButton(mView, mReminderItems, mModel.mCalendarMaxReminders);
- }
-
- // From com.google.android.gm.ComposeActivity
- private MultiAutoCompleteTextView initMultiAutoCompleteTextView(RecipientEditTextView list) {
- if (ChipsUtil.supportsChipsUi()) {
- mAddressAdapter = new RecipientAdapter(mActivity);
- list.setAdapter((BaseRecipientAdapter) mAddressAdapter);
- list.setOnFocusListShrinkRecipients(false);
- } else {
- mAddressAdapter = new EmailAddressAdapter(mActivity);
- list.setAdapter((EmailAddressAdapter)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 setDate(TextView view, long millis) {
- int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR
- | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_MONTH
- | DateUtils.FORMAT_ABBREV_WEEKDAY;
-
- // Unfortunately, DateUtils doesn't support a timezone other than the
- // default timezone provided by the system, so we have this ugly hack
- // here to trick it into formatting our time correctly. In order to
- // prevent all sorts of craziness, we synchronize on the TimeZone class
- // to prevent other threads from reading an incorrect timezone from
- // calls to TimeZone#getDefault()
- // TODO fix this if/when DateUtils allows for passing in a timezone
- String dateString;
- synchronized (TimeZone.class) {
- TimeZone.setDefault(TimeZone.getTimeZone(mTimezone));
- dateString = DateUtils.formatDateTime(mActivity, millis, flags);
- // setting the default back to null restores the correct behavior
- TimeZone.setDefault(null);
- }
- view.setText(dateString);
- }
-
- private void setTime(TextView view, long millis) {
- int flags = DateUtils.FORMAT_SHOW_TIME;
- flags |= DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
- if (DateFormat.is24HourFormat(mActivity)) {
- flags |= DateUtils.FORMAT_24HOUR;
- }
-
- // Unfortunately, DateUtils doesn't support a timezone other than the
- // default timezone provided by the system, so we have this ugly hack
- // here to trick it into formatting our time correctly. In order to
- // prevent all sorts of craziness, we synchronize on the TimeZone class
- // to prevent other threads from reading an incorrect timezone from
- // calls to TimeZone#getDefault()
- // TODO fix this if/when DateUtils allows for passing in a timezone
- String timeString;
- synchronized (TimeZone.class) {
- TimeZone.setDefault(TimeZone.getTimeZone(mTimezone));
- timeString = DateUtils.formatDateTime(mActivity, millis, flags);
- TimeZone.setDefault(null);
- }
- view.setText(timeString);
- }
-
- /**
- * @param isChecked
- */
- protected void setAllDayViewsVisibility(boolean isChecked) {
- if (isChecked) {
- if (mEndTime.hour == 0 && mEndTime.minute == 0) {
- if (mAllDay != isChecked) {
- mEndTime.monthDay--;
- }
-
- long endMillis = mEndTime.normalize(true);
-
- // Do not allow an event to have an end time
- // before the
- // start time.
- if (mEndTime.before(mStartTime)) {
- mEndTime.set(mStartTime);
- endMillis = mEndTime.normalize(true);
- }
- setDate(mEndDateButton, endMillis);
- setTime(mEndTimeButton, endMillis);
- }
-
- mStartTimeButton.setVisibility(View.GONE);
- mEndTimeButton.setVisibility(View.GONE);
- mTimezoneRow.setVisibility(View.GONE);
- } else {
- if (mEndTime.hour == 0 && mEndTime.minute == 0) {
- if (mAllDay != isChecked) {
- mEndTime.monthDay++;
- }
-
- long endMillis = mEndTime.normalize(true);
- setDate(mEndDateButton, endMillis);
- setTime(mEndTimeButton, endMillis);
- }
- mStartTimeButton.setVisibility(View.VISIBLE);
- mEndTimeButton.setVisibility(View.VISIBLE);
- mTimezoneRow.setVisibility(View.VISIBLE);
- }
-
- // If this is a new event, and if availability has not yet been
- // explicitly set, toggle busy/available as the inverse of all day.
- if (mModel.mUri == null && !mAvailabilityExplicitlySet) {
- // Values are from R.arrays.availability_values.
- // 0 = busy
- // 1 = available
- int newAvailabilityValue = isChecked? 1 : 0;
- if (mAvailabilityAdapter != null && mAvailabilityValues != null
- && mAvailabilityValues.contains(newAvailabilityValue)) {
- // We'll need to let the spinner's listener know that we're
- // explicitly toggling it.
- mAllDayChangingAvailability = true;
-
- String newAvailabilityLabel = mOriginalAvailabilityLabels.get(newAvailabilityValue);
- int newAvailabilityPos = mAvailabilityAdapter.getPosition(newAvailabilityLabel);
- mAvailabilitySpinner.setSelection(newAvailabilityPos);
- }
- }
-
- mAllDay = isChecked;
- updateHomeTime();
- }
-
- public void setColorPickerButtonStates(int[] colorArray) {
- setColorPickerButtonStates(colorArray != null && colorArray.length > 0);
- }
-
- public void setColorPickerButtonStates(boolean showColorPalette) {
- if (showColorPalette) {
- mColorPickerNewEvent.setVisibility(View.VISIBLE);
- mColorPickerExistingEvent.setVisibility(View.VISIBLE);
- } else {
- mColorPickerNewEvent.setVisibility(View.INVISIBLE);
- mColorPickerExistingEvent.setVisibility(View.GONE);
- }
- }
-
- public boolean isColorPaletteVisible() {
- return mColorPickerNewEvent.getVisibility() == View.VISIBLE ||
- mColorPickerExistingEvent.getVisibility() == View.VISIBLE;
- }
-
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- // This is only used for the Calendar spinner in new events, and only fires when the
- // calendar selection changes or on screen rotation
- Cursor c = (Cursor) parent.getItemAtPosition(position);
- if (c == null) {
- // TODO: can this happen? should we drop this check?
- Log.w(TAG, "Cursor not set on calendar item");
- return;
- }
-
- // Do nothing if the selection didn't change so that reminders will not get lost
- int idColumn = c.getColumnIndexOrThrow(Calendars._ID);
- long calendarId = c.getLong(idColumn);
- int colorColumn = c.getColumnIndexOrThrow(Calendars.CALENDAR_COLOR);
- int color = c.getInt(colorColumn);
- int displayColor = Utils.getDisplayColorFromColor(color);
-
- // Prevents resetting of data (reminders, etc.) on orientation change.
- if (calendarId == mModel.mCalendarId && mModel.isCalendarColorInitialized() &&
- displayColor == mModel.getCalendarColor()) {
- return;
- }
-
- setSpinnerBackgroundColor(displayColor);
-
- mModel.mCalendarId = calendarId;
- mModel.setCalendarColor(displayColor);
- mModel.mCalendarAccountName = c.getString(EditEventHelper.CALENDARS_INDEX_ACCOUNT_NAME);
- mModel.mCalendarAccountType = c.getString(EditEventHelper.CALENDARS_INDEX_ACCOUNT_TYPE);
- mModel.setEventColor(mModel.getCalendarColor());
-
- setColorPickerButtonStates(mModel.getCalendarEventColors());
-
- // Update the max/allowed reminders with the new calendar properties.
- int maxRemindersColumn = c.getColumnIndexOrThrow(Calendars.MAX_REMINDERS);
- mModel.mCalendarMaxReminders = c.getInt(maxRemindersColumn);
- int allowedRemindersColumn = c.getColumnIndexOrThrow(Calendars.ALLOWED_REMINDERS);
- mModel.mCalendarAllowedReminders = c.getString(allowedRemindersColumn);
- int allowedAttendeeTypesColumn = c.getColumnIndexOrThrow(Calendars.ALLOWED_ATTENDEE_TYPES);
- mModel.mCalendarAllowedAttendeeTypes = c.getString(allowedAttendeeTypesColumn);
- int allowedAvailabilityColumn = c.getColumnIndexOrThrow(Calendars.ALLOWED_AVAILABILITY);
- mModel.mCalendarAllowedAvailability = c.getString(allowedAvailabilityColumn);
-
- // Discard the current reminders and replace them with the model's default reminder set.
- // We could attempt to save & restore the reminders that have been added, but that's
- // probably more trouble than it's worth.
- mModel.mReminders.clear();
- mModel.mReminders.addAll(mModel.mDefaultReminders);
- mModel.mHasAlarm = mModel.mReminders.size() != 0;
-
- // Update the UI elements.
- mReminderItems.clear();
- LinearLayout reminderLayout =
- (LinearLayout) mScrollView.findViewById(R.id.reminder_items_container);
- reminderLayout.removeAllViews();
- prepareReminders();
- prepareAvailability();
- }
-
- /**
- * Checks if the start and end times for this event should be displayed in
- * the Calendar app's time zone as well and formats and displays them.
- */
- private void updateHomeTime() {
- String tz = Utils.getTimeZone(mActivity, null);
- if (!mAllDayCheckBox.isChecked() && !TextUtils.equals(tz, mTimezone)
- && mModification != EditEventHelper.MODIFY_UNINITIALIZED) {
- int flags = DateUtils.FORMAT_SHOW_TIME;
- boolean is24Format = DateFormat.is24HourFormat(mActivity);
- if (is24Format) {
- flags |= DateUtils.FORMAT_24HOUR;
- }
- long millisStart = mStartTime.toMillis(false);
- long millisEnd = mEndTime.toMillis(false);
-
- boolean isDSTStart = mStartTime.isDst != 0;
- boolean isDSTEnd = mEndTime.isDst != 0;
-
- // First update the start date and times
- String tzDisplay = TimeZone.getTimeZone(tz).getDisplayName(
- isDSTStart, TimeZone.SHORT, Locale.getDefault());
- StringBuilder time = new StringBuilder();
-
- mSB.setLength(0);
- time.append(DateUtils
- .formatDateRange(mActivity, mF, millisStart, millisStart, flags, tz))
- .append(" ").append(tzDisplay);
- mStartTimeHome.setText(time.toString());
-
- flags = DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_DATE
- | DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_WEEKDAY;
- mSB.setLength(0);
- mStartDateHome
- .setText(DateUtils.formatDateRange(
- mActivity, mF, millisStart, millisStart, flags, tz).toString());
-
- // Make any adjustments needed for the end times
- if (isDSTEnd != isDSTStart) {
- tzDisplay = TimeZone.getTimeZone(tz).getDisplayName(
- isDSTEnd, TimeZone.SHORT, Locale.getDefault());
- }
- flags = DateUtils.FORMAT_SHOW_TIME;
- if (is24Format) {
- flags |= DateUtils.FORMAT_24HOUR;
- }
-
- // Then update the end times
- time.setLength(0);
- mSB.setLength(0);
- time.append(DateUtils.formatDateRange(
- mActivity, mF, millisEnd, millisEnd, flags, tz)).append(" ").append(tzDisplay);
- mEndTimeHome.setText(time.toString());
-
- flags = DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_DATE
- | DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_WEEKDAY;
- mSB.setLength(0);
- mEndDateHome.setText(DateUtils.formatDateRange(
- mActivity, mF, millisEnd, millisEnd, flags, tz).toString());
-
- mStartHomeGroup.setVisibility(View.VISIBLE);
- mEndHomeGroup.setVisibility(View.VISIBLE);
- } else {
- mStartHomeGroup.setVisibility(View.GONE);
- mEndHomeGroup.setVisibility(View.GONE);
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- }
-}
diff --git a/src/com/android/calendar/event/EventColorCache.java b/src/com/android/calendar/event/EventColorCache.java
deleted file mode 100644
index 8fc03701..00000000
--- a/src/com/android/calendar/event/EventColorCache.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2013 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.event;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A cache for event colors and event color keys stored based upon calendar account name and type.
- */
-public class EventColorCache implements Serializable {
-
- private static final long serialVersionUID = 2L;
-
- private static final String SEPARATOR = "::";
-
- private Map<String, ArrayList<Integer>> mColorPaletteMap;
- private Map<String, Integer> mColorKeyMap;
-
- public EventColorCache() {
- mColorPaletteMap = new HashMap<String, ArrayList<Integer>>();
- mColorKeyMap = new HashMap<String, Integer>();
- }
-
- /**
- * Inserts a color into the cache.
- */
- public void insertColor(String accountName, String accountType, int displayColor,
- int colorKey) {
- mColorKeyMap.put(createKey(accountName, accountType, displayColor), colorKey);
- String key = createKey(accountName, accountType);
- ArrayList<Integer> colorPalette;
- if ((colorPalette = mColorPaletteMap.get(key)) == null) {
- colorPalette = new ArrayList<Integer>();
- }
- colorPalette.add(displayColor);
- mColorPaletteMap.put(key, colorPalette);
- }
-
- /**
- * Retrieve an array of colors for a specific account name and type.
- */
- public int[] getColorArray(String accountName, String accountType) {
- ArrayList<Integer> colors = mColorPaletteMap.get(createKey(accountName, accountType));
- if (colors == null) {
- return null;
- }
- int[] ret = new int[colors.size()];
- for (int i = 0; i < ret.length; i++) {
- ret[i] = colors.get(i);
- }
- return ret;
- }
-
- /**
- * Retrieve an event color's unique key based on account name, type, and color.
- */
- public int getColorKey(String accountName, String accountType, int displayColor) {
- return mColorKeyMap.get(createKey(accountName, accountType, displayColor));
- }
-
- /**
- * Sorts the arrays of colors based on a comparator.
- */
- public void sortPalettes(Comparator<Integer> comparator) {
- for (String key : mColorPaletteMap.keySet()) {
- ArrayList<Integer> palette = mColorPaletteMap.get(key);
- Integer[] sortedColors = new Integer[palette.size()];
- Arrays.sort(palette.toArray(sortedColors), comparator);
- palette.clear();
- for (Integer color : sortedColors) {
- palette.add(color);
- }
- mColorPaletteMap.put(key, palette);
- }
- }
-
- private String createKey(String accountName, String accountType) {
- return new StringBuilder().append(accountName)
- .append(SEPARATOR)
- .append(accountType)
- .toString();
- }
-
- private String createKey(String accountName, String accountType, int displayColor) {
- return new StringBuilder(createKey(accountName, accountType))
- .append(SEPARATOR)
- .append(displayColor)
- .toString();
- }
-}
diff --git a/src/com/android/calendar/event/EventColorPickerDialog.java b/src/com/android/calendar/event/EventColorPickerDialog.java
deleted file mode 100644
index 5a6b2685..00000000
--- a/src/com/android/calendar/event/EventColorPickerDialog.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2013 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.event;
-
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-
-import com.android.calendar.R;
-import com.android.colorpicker.ColorPickerDialog;
-
-/**
- * A dialog which displays event colors, with an additional button for the calendar color.
- */
-public class EventColorPickerDialog extends ColorPickerDialog {
-
- private static final int NUM_COLUMNS = 4;
- private static final String KEY_CALENDAR_COLOR = "calendar_color";
-
- private int mCalendarColor;
-
- public EventColorPickerDialog() {
- // Empty constructor required for dialog fragment.
- }
-
- public static EventColorPickerDialog newInstance(int[] colors, int selectedColor,
- int calendarColor, boolean isTablet) {
- EventColorPickerDialog ret = new EventColorPickerDialog();
- ret.initialize(R.string.event_color_picker_dialog_title, colors, selectedColor, NUM_COLUMNS,
- isTablet ? SIZE_LARGE : SIZE_SMALL);
- ret.setCalendarColor(calendarColor);
- return ret;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (savedInstanceState != null) {
- mCalendarColor = savedInstanceState.getInt(KEY_CALENDAR_COLOR);
- }
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putInt(KEY_CALENDAR_COLOR, mCalendarColor);
- }
-
- public void setCalendarColor(int color) {
- mCalendarColor = color;
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- Dialog dialog = super.onCreateDialog(savedInstanceState);
- mAlertDialog.setButton(DialogInterface.BUTTON_NEUTRAL,
- getActivity().getString(R.string.event_color_set_to_default),
- new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- onColorSelected(mCalendarColor);
- }
- }
- );
- return dialog;
- }
-}
diff --git a/src/com/android/calendar/event/EventLocationAdapter.java b/src/com/android/calendar/event/EventLocationAdapter.java
deleted file mode 100644
index 3bcb3acd..00000000
--- a/src/com/android/calendar/event/EventLocationAdapter.java
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * Copyright (C) 2012 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.event;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.provider.CalendarContract.Events;
-import android.provider.ContactsContract.CommonDataKinds;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.RawContacts;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.Filter;
-import android.widget.Filterable;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.calendar.R;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeSet;
-import java.util.concurrent.ExecutionException;
-
-// TODO: limit length of dropdown to stop at the soft keyboard
-// TODO: history icon resize asset
-
-/**
- * An adapter for autocomplete of the location field in edit-event view.
- */
-public class EventLocationAdapter extends ArrayAdapter<EventLocationAdapter.Result>
- implements Filterable {
- private static final String TAG = "EventLocationAdapter";
-
- /**
- * Internal class for containing info for an item in the auto-complete results.
- */
- public static class Result {
- private final String mName;
- private final String mAddress;
-
- // The default image resource for the icon. This will be null if there should
- // be no icon (if multiple listings for a contact, only the first one should have the
- // photo icon).
- private final Integer mDefaultIcon;
-
- // The contact photo to use for the icon. This will override the default icon.
- private final Uri mContactPhotoUri;
-
- public Result(String displayName, String address, Integer defaultIcon,
- Uri contactPhotoUri) {
- this.mName = displayName;
- this.mAddress = address;
- this.mDefaultIcon = defaultIcon;
- this.mContactPhotoUri = contactPhotoUri;
- }
-
- /**
- * This is the autocompleted text.
- */
- @Override
- public String toString() {
- return mAddress;
- }
- }
- private static ArrayList<Result> EMPTY_LIST = new ArrayList<Result>();
-
- // Constants for contacts query:
- // SELECT ... FROM view_data data WHERE ((data1 LIKE 'input%' OR data1 LIKE '%input%' OR
- // display_name LIKE 'input%' OR display_name LIKE '%input%' )) ORDER BY display_name ASC
- private static final String[] CONTACTS_PROJECTION = new String[] {
- CommonDataKinds.StructuredPostal._ID,
- Contacts.DISPLAY_NAME,
- CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS,
- RawContacts.CONTACT_ID,
- Contacts.PHOTO_ID,
- };
- private static final int CONTACTS_INDEX_ID = 0;
- private static final int CONTACTS_INDEX_DISPLAY_NAME = 1;
- private static final int CONTACTS_INDEX_ADDRESS = 2;
- private static final int CONTACTS_INDEX_CONTACT_ID = 3;
- private static final int CONTACTS_INDEX_PHOTO_ID = 4;
- // TODO: Only query visible contacts?
- private static final String CONTACTS_WHERE = new StringBuilder()
- .append("(")
- .append(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS)
- .append(" LIKE ? OR ")
- .append(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS)
- .append(" LIKE ? OR ")
- .append(Contacts.DISPLAY_NAME)
- .append(" LIKE ? OR ")
- .append(Contacts.DISPLAY_NAME)
- .append(" LIKE ? )")
- .toString();
-
- // Constants for recent locations query (in Events table):
- // SELECT ... FROM view_events WHERE (eventLocation LIKE 'input%') ORDER BY _id DESC
- private static final String[] EVENT_PROJECTION = new String[] {
- Events._ID,
- Events.EVENT_LOCATION,
- Events.VISIBLE,
- };
- private static final int EVENT_INDEX_ID = 0;
- private static final int EVENT_INDEX_LOCATION = 1;
- private static final int EVENT_INDEX_VISIBLE = 2;
- private static final String LOCATION_WHERE = Events.VISIBLE + "=? AND "
- + Events.EVENT_LOCATION + " LIKE ?";
- private static final int MAX_LOCATION_SUGGESTIONS = 4;
-
- private final ContentResolver mResolver;
- private final LayoutInflater mInflater;
- private final ArrayList<Result> mResultList = new ArrayList<Result>();
-
- // The cache for contacts photos. We don't have to worry about clearing this, as a
- // new adapter is created for every edit event.
- private final Map<Uri, Bitmap> mPhotoCache = new HashMap<Uri, Bitmap>();
-
- /**
- * Constructor.
- */
- public EventLocationAdapter(Context context) {
- super(context, R.layout.location_dropdown_item, EMPTY_LIST);
-
- mResolver = context.getContentResolver();
- mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- }
-
- @Override
- public int getCount() {
- return mResultList.size();
- }
-
- @Override
- public Result getItem(int index) {
- if (index < mResultList.size()) {
- return mResultList.get(index);
- } else {
- return null;
- }
- }
-
- @Override
- public View getView(final int position, final View convertView, final ViewGroup parent) {
- View view = convertView;
- if (view == null) {
- view = mInflater.inflate(R.layout.location_dropdown_item, parent, false);
- }
- final Result result = getItem(position);
- if (result == null) {
- return view;
- }
-
- // Update the display name in the item in auto-complete list.
- TextView nameView = (TextView) view.findViewById(R.id.location_name);
- if (nameView != null) {
- if (result.mName == null) {
- nameView.setVisibility(View.GONE);
- } else {
- nameView.setVisibility(View.VISIBLE);
- nameView.setText(result.mName);
- }
- }
-
- // Update the address line.
- TextView addressView = (TextView) view.findViewById(R.id.location_address);
- if (addressView != null) {
- addressView.setText(result.mAddress);
- }
-
- // Update the icon.
- final ImageView imageView = (ImageView) view.findViewById(R.id.icon);
- if (imageView != null) {
- if (result.mDefaultIcon == null) {
- imageView.setVisibility(View.INVISIBLE);
- } else {
- imageView.setVisibility(View.VISIBLE);
- imageView.setImageResource(result.mDefaultIcon);
-
- // Save the URI on the view, so we can check against it later when updating
- // the image. Otherwise the async image update with using 'convertView' above
- // resulted in the wrong list items being updated.
- imageView.setTag(result.mContactPhotoUri);
- if (result.mContactPhotoUri != null) {
- Bitmap cachedPhoto = mPhotoCache.get(result.mContactPhotoUri);
- if (cachedPhoto != null) {
- // Use photo in cache.
- imageView.setImageBitmap(cachedPhoto);
- } else {
- // Asynchronously load photo and update.
- asyncLoadPhotoAndUpdateView(result.mContactPhotoUri, imageView);
- }
- }
- }
- }
- return view;
- }
-
- // TODO: Refactor to share code with ContactsAsyncHelper.
- private void asyncLoadPhotoAndUpdateView(final Uri contactPhotoUri,
- final ImageView imageView) {
- AsyncTask<Void, Void, Bitmap> photoUpdaterTask =
- new AsyncTask<Void, Void, Bitmap>() {
- @Override
- protected Bitmap doInBackground(Void... params) {
- Bitmap photo = null;
- InputStream imageStream = Contacts.openContactPhotoInputStream(
- mResolver, contactPhotoUri);
- if (imageStream != null) {
- photo = BitmapFactory.decodeStream(imageStream);
- mPhotoCache.put(contactPhotoUri, photo);
- }
- return photo;
- }
-
- @Override
- public void onPostExecute(Bitmap photo) {
- // The View may have already been reused (because using 'convertView' above), so
- // we must check the URI is as expected before setting the icon, or we may be
- // setting the icon in other items.
- if (photo != null && imageView.getTag() == contactPhotoUri) {
- imageView.setImageBitmap(photo);
- }
- }
- }.execute();
- }
-
- /**
- * Return filter for matching against contacts info and recent locations.
- */
- @Override
- public Filter getFilter() {
- return new LocationFilter();
- }
-
- /**
- * Filter implementation for matching the input string against contacts info and
- * recent locations.
- */
- public class LocationFilter extends Filter {
-
- @Override
- protected FilterResults performFiltering(CharSequence constraint) {
- long startTime = System.currentTimeMillis();
- final String filter = constraint == null ? "" : constraint.toString();
- if (filter.isEmpty()) {
- return null;
- }
-
- // Start the recent locations query (async).
- AsyncTask<Void, Void, List<Result>> locationsQueryTask =
- new AsyncTask<Void, Void, List<Result>>() {
- @Override
- protected List<Result> doInBackground(Void... params) {
- return queryRecentLocations(mResolver, filter);
- }
- }.execute();
-
- // Perform the contacts query (sync).
- HashSet<String> contactsAddresses = new HashSet<String>();
- List<Result> contacts = queryContacts(mResolver, filter, contactsAddresses);
-
- ArrayList<Result> resultList = new ArrayList<Result>();
- try {
- // Wait for the locations query.
- List<Result> recentLocations = locationsQueryTask.get();
-
- // Add the matched recent locations to returned results. If a match exists in
- // both the recent locations query and the contacts addresses, only display it
- // as a contacts match.
- for (Result recentLocation : recentLocations) {
- if (recentLocation.mAddress != null &&
- !contactsAddresses.contains(recentLocation.mAddress)) {
- resultList.add(recentLocation);
- }
- }
- } catch (ExecutionException e) {
- Log.e(TAG, "Failed waiting for locations query results.", e);
- } catch (InterruptedException e) {
- Log.e(TAG, "Failed waiting for locations query results.", e);
- }
-
- // Add all the contacts matches to returned results.
- if (contacts != null) {
- resultList.addAll(contacts);
- }
-
- // Log the processing duration.
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- long duration = System.currentTimeMillis() - startTime;
- StringBuilder msg = new StringBuilder();
- msg.append("Autocomplete of ").append(constraint);
- msg.append(": location query match took ").append(duration).append("ms ");
- msg.append("(").append(resultList.size()).append(" results)");
- Log.d(TAG, msg.toString());
- }
-
- final FilterResults filterResults = new FilterResults();
- filterResults.values = resultList;
- filterResults.count = resultList.size();
- return filterResults;
- }
-
- @Override
- protected void publishResults(CharSequence constraint, FilterResults results) {
- mResultList.clear();
- if (results != null && results.count > 0) {
- mResultList.addAll((ArrayList<Result>) results.values);
- notifyDataSetChanged();
- } else {
- notifyDataSetInvalidated();
- }
- }
- }
-
- /**
- * Matches the input string against contacts names and addresses.
- *
- * @param resolver The content resolver.
- * @param input The user-typed input string.
- * @param addressesRetVal The addresses in the returned result are also returned here
- * for faster lookup. Pass in an empty set.
- * @return Ordered list of all the matched results. If there are multiple address matches
- * for the same contact, they will be listed together in individual items, with only
- * the first item containing a name/icon.
- */
- private static List<Result> queryContacts(ContentResolver resolver, String input,
- HashSet<String> addressesRetVal) {
- String where = null;
- String[] whereArgs = null;
-
- // Match any word in contact name or address.
- if (!TextUtils.isEmpty(input)) {
- where = CONTACTS_WHERE;
- String param1 = input + "%";
- String param2 = "% " + input + "%";
- whereArgs = new String[] {param1, param2, param1, param2};
- }
-
- // Perform the query.
- Cursor c = resolver.query(CommonDataKinds.StructuredPostal.CONTENT_URI,
- CONTACTS_PROJECTION, where, whereArgs, Contacts.DISPLAY_NAME + " ASC");
-
- // Process results. Group together addresses for the same contact.
- try {
- Map<String, List<Result>> nameToAddresses = new HashMap<String, List<Result>>();
- c.moveToPosition(-1);
- while (c.moveToNext()) {
- String name = c.getString(CONTACTS_INDEX_DISPLAY_NAME);
- String address = c.getString(CONTACTS_INDEX_ADDRESS);
- if (name != null) {
-
- List<Result> addressesForName = nameToAddresses.get(name);
- Result result;
- if (addressesForName == null) {
- // Determine if there is a photo for the icon.
- Uri contactPhotoUri = null;
- if (c.getLong(CONTACTS_INDEX_PHOTO_ID) > 0) {
- contactPhotoUri = ContentUris.withAppendedId(Contacts.CONTENT_URI,
- c.getLong(CONTACTS_INDEX_CONTACT_ID));
- }
-
- // First listing for a distinct contact should have the name/icon.
- addressesForName = new ArrayList<Result>();
- nameToAddresses.put(name, addressesForName);
- result = new Result(name, address, R.drawable.ic_contact_picture,
- contactPhotoUri);
- } else {
- // Do not include name/icon in subsequent listings for the same contact.
- result = new Result(null, address, null, null);
- }
-
- addressesForName.add(result);
- addressesRetVal.add(address);
- }
- }
-
- // Return the list of results.
- List<Result> allResults = new ArrayList<Result>();
- for (List<Result> result : nameToAddresses.values()) {
- allResults.addAll(result);
- }
- return allResults;
-
- } finally {
- if (c != null) {
- c.close();
- }
- }
- }
-
- /**
- * Matches the input string against recent locations.
- */
- private static List<Result> queryRecentLocations(ContentResolver resolver, String input) {
- // TODO: also match each word in the address?
- String filter = input == null ? "" : input + "%";
- if (filter.isEmpty()) {
- return null;
- }
-
- // Query all locations prefixed with the constraint. There is no way to insert
- // 'DISTINCT' or 'GROUP BY' to get rid of dupes, so use post-processing to
- // remove dupes. We will order query results by descending event ID to show
- // results that were most recently inputed.
- Cursor c = resolver.query(Events.CONTENT_URI, EVENT_PROJECTION, LOCATION_WHERE,
- new String[] { "1", filter }, Events._ID + " DESC");
- try {
- List<Result> recentLocations = null;
- if (c != null) {
- // Post process query results.
- recentLocations = processLocationsQueryResults(c);
- }
- return recentLocations;
- } finally {
- if (c != null) {
- c.close();
- }
- }
- }
-
- /**
- * Post-process the query results to return the first MAX_LOCATION_SUGGESTIONS
- * unique locations in alphabetical order.
- *
- * TODO: Refactor to share code with the recent titles auto-complete.
- */
- private static List<Result> processLocationsQueryResults(Cursor cursor) {
- TreeSet<String> locations = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
- cursor.moveToPosition(-1);
-
- // Remove dupes.
- while ((locations.size() < MAX_LOCATION_SUGGESTIONS) && cursor.moveToNext()) {
- String location = cursor.getString(EVENT_INDEX_LOCATION).trim();
- locations.add(location);
- }
-
- // Copy the sorted results.
- List<Result> results = new ArrayList<Result>();
- for (String location : locations) {
- results.add(new Result(null, location, R.drawable.ic_history_holo_light, null));
- }
- return results;
- }
-}
diff --git a/src/com/android/calendar/event/EventViewUtils.java b/src/com/android/calendar/event/EventViewUtils.java
deleted file mode 100644
index e5bdb4b9..00000000
--- a/src/com/android/calendar/event/EventViewUtils.java
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.calendar.event;
-
-import com.android.calendar.CalendarEventModel.ReminderEntry;
-import com.android.calendar.R;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ArrayAdapter;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
-import android.widget.Spinner;
-
-import java.util.ArrayList;
-
-public class EventViewUtils {
- private static final String TAG = "EventViewUtils";
-
- private EventViewUtils() {
- }
-
- // 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
- // "2 hours".
- public static String constructReminderLabel(Context context, int minutes, boolean abbrev) {
- Resources resources = context.getResources();
- int value, resId;
-
- if (minutes % 60 != 0) {
- value = minutes;
- if (abbrev) {
- resId = R.plurals.Nmins;
- } else {
- resId = R.plurals.Nminutes;
- }
- } else if (minutes % (24 * 60) != 0) {
- value = minutes / 60;
- resId = R.plurals.Nhours;
- } else {
- value = minutes / (24 * 60);
- resId = R.plurals.Ndays;
- }
-
- String format = resources.getQuantityString(resId, value);
- return String.format(format, value);
- }
-
- /**
- * 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
- */
- public static int findMinutesInReminderList(ArrayList<Integer> values, int minutes) {
- int index = values.indexOf(minutes);
- if (index == -1) {
- // This should never happen.
- Log.e(TAG, "Cannot find minutes (" + minutes + ") in list");
- return 0;
- }
- return index;
- }
-
- /**
- * Finds the index of the given method in the "methods" list. If the method isn't present
- * (perhaps because we don't think it's allowed for this calendar), we return zero (the
- * first item in the list).
- * <p>
- * With the current definitions, this effectively converts DEFAULT and unsupported method
- * types to ALERT.
- *
- * @param values the list of minutes corresponding to the spinner choices
- * @param method the method to search for in the values list
- * @return the index of the method in the "values" list
- */
- public static int findMethodInReminderList(ArrayList<Integer> values, int method) {
- int index = values.indexOf(method);
- if (index == -1) {
- // If not allowed, or undefined, just use the first entry in the list.
- //Log.d(TAG, "Cannot find method (" + method + ") in allowed list");
- index = 0;
- }
- return index;
- }
-
- /**
- * Extracts reminder minutes info from UI elements.
- *
- * @param reminderItems UI elements (layouts with spinners) that hold array indices.
- * @param reminderMinuteValues Maps array index to time in minutes.
- * @param reminderMethodValues Maps array index to alert method constant.
- * @return Array with reminder data.
- */
- public static ArrayList<ReminderEntry> reminderItemsToReminders(
- ArrayList<LinearLayout> reminderItems, ArrayList<Integer> reminderMinuteValues,
- ArrayList<Integer> reminderMethodValues) {
- int len = reminderItems.size();
- ArrayList<ReminderEntry> reminders = new ArrayList<ReminderEntry>(len);
- for (int index = 0; index < len; index++) {
- LinearLayout layout = reminderItems.get(index);
- Spinner minuteSpinner = (Spinner) layout.findViewById(R.id.reminder_minutes_value);
- Spinner methodSpinner = (Spinner) layout.findViewById(R.id.reminder_method_value);
- int minutes = reminderMinuteValues.get(minuteSpinner.getSelectedItemPosition());
- int method = reminderMethodValues.get(methodSpinner.getSelectedItemPosition());
- reminders.add(ReminderEntry.valueOf(minutes, method));
- }
- return reminders;
- }
-
- /**
- * If "minutes" is not currently present in "values", we add an appropriate new entry
- * to values and labels.
- */
- public 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++) {
- if (minutes < values.get(i)) {
- values.add(i, minutes);
- labels.add(i, label);
- return;
- }
- }
-
- values.add(minutes);
- labels.add(len, label);
- }
-
- /**
- * Remove entries from the method list that aren't allowed for this calendar.
- *
- * @param values List of known method values.
- * @param labels List of known method labels.
- * @param allowedMethods Has the form "0,1,3", indicating method constants from Reminders.
- */
- public static void reduceMethodList(ArrayList<Integer> values, ArrayList<String> labels,
- String allowedMethods)
- {
- // Parse "allowedMethods".
- String[] allowedStrings = allowedMethods.split(",");
- int[] allowedValues = new int[allowedStrings.length];
-
- for (int i = 0; i < allowedValues.length; i++) {
- try {
- allowedValues[i] = Integer.parseInt(allowedStrings[i], 10);
- } catch (NumberFormatException nfe) {
- Log.w(TAG, "Bad allowed-strings list: '" + allowedStrings[i] +
- "' in '" + allowedMethods + "'");
- return;
- }
- }
-
- // Walk through the method list, removing entries that aren't in the allowed list.
- for (int i = values.size() - 1; i >= 0; i--) {
- int val = values.get(i);
- int j;
-
- for (j = allowedValues.length - 1; j >= 0; j--) {
- if (val == allowedValues[j]) {
- break;
- }
- }
- if (j < 0) {
- values.remove(i);
- labels.remove(i);
- }
- }
- }
-
- /**
- * Set the list of labels on a reminder spinner.
- */
- private static void setReminderSpinnerLabels(Activity activity, Spinner spinner,
- ArrayList<String> labels) {
- Resources res = activity.getResources();
- spinner.setPrompt(res.getString(R.string.reminders_label));
- int resource = android.R.layout.simple_spinner_item;
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(activity, resource, labels);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- spinner.setAdapter(adapter);
- }
-
- /**
- * Adds a reminder to the displayed list of reminders. The values/labels
- * arrays must not change after calling here, or the spinners we created
- * might index into the wrong entry. Returns true if successfully added
- * reminder, false if no reminders can be added.
- *
- * onItemSelected allows a listener to be set for any changes to the
- * spinners in the reminder. If a listener is set it will store the
- * initial position of the spinner into the spinner's tag for comparison
- * with any new position setting.
- */
- public static boolean addReminder(Activity activity, View view, View.OnClickListener listener,
- ArrayList<LinearLayout> items, ArrayList<Integer> minuteValues,
- ArrayList<String> minuteLabels, ArrayList<Integer> methodValues,
- ArrayList<String> methodLabels, ReminderEntry newReminder, int maxReminders,
- OnItemSelectedListener onItemSelected) {
-
- if (items.size() >= maxReminders) {
- return false;
- }
-
- LayoutInflater inflater = activity.getLayoutInflater();
- LinearLayout parent = (LinearLayout) view.findViewById(R.id.reminder_items_container);
- LinearLayout reminderItem = (LinearLayout) inflater.inflate(R.layout.edit_reminder_item,
- null);
- parent.addView(reminderItem);
-
- ImageButton reminderRemoveButton;
- reminderRemoveButton = (ImageButton) reminderItem.findViewById(R.id.reminder_remove);
- reminderRemoveButton.setOnClickListener(listener);
-
- /*
- * The spinner has the default set of labels from the string resource file, but we
- * want to drop in our custom set of labels because it may have additional entries.
- */
- Spinner spinner = (Spinner) reminderItem.findViewById(R.id.reminder_minutes_value);
- setReminderSpinnerLabels(activity, spinner, minuteLabels);
-
- int index = findMinutesInReminderList(minuteValues, newReminder.getMinutes());
- spinner.setSelection(index);
-
- if (onItemSelected != null) {
- spinner.setTag(index);
- spinner.setOnItemSelectedListener(onItemSelected);
- }
-
- /*
- * Configure the alert-method spinner. Methods not supported by the current Calendar
- * will not be shown.
- */
- spinner = (Spinner) reminderItem.findViewById(R.id.reminder_method_value);
- setReminderSpinnerLabels(activity, spinner, methodLabels);
-
- index = findMethodInReminderList(methodValues, newReminder.getMethod());
- spinner.setSelection(index);
-
- if (onItemSelected != null) {
- spinner.setTag(index);
- spinner.setOnItemSelectedListener(onItemSelected);
- }
-
- items.add(reminderItem);
-
- return true;
- }
-
- /**
- * Enables/disables the 'add reminder' button depending on the current number of
- * reminders.
- */
- public static void updateAddReminderButton(View view, ArrayList<LinearLayout> reminders,
- int maxReminders) {
- View reminderAddButton = view.findViewById(R.id.reminder_add);
- if (reminderAddButton != null) {
- if (reminders.size() >= maxReminders) {
- reminderAddButton.setEnabled(false);
- reminderAddButton.setVisibility(View.GONE);
- } else {
- reminderAddButton.setEnabled(true);
- reminderAddButton.setVisibility(View.VISIBLE);
- }
- }
- }
-}
diff --git a/src/com/android/calendar/month/MonthByWeekAdapter.java b/src/com/android/calendar/month/MonthByWeekAdapter.java
index 64b734fa..45a1bea1 100644
--- a/src/com/android/calendar/month/MonthByWeekAdapter.java
+++ b/src/com/android/calendar/month/MonthByWeekAdapter.java
@@ -80,9 +80,8 @@ public class MonthByWeekAdapter extends SimpleWeeksAdapter {
// Minimal distance to move the finger in order to cancel the click animation
private static float mMovedPixelToCancel;
- public MonthByWeekAdapter(Context context, HashMap<String, Integer> params, Handler handler) {
+ public MonthByWeekAdapter(Context context, HashMap<String, Integer> params) {
super(context, params);
- mEventDialogHandler = handler;
if (params.containsKey(WEEK_PARAMS_IS_MINI)) {
mIsMiniMonth = params.get(WEEK_PARAMS_IS_MINI) != 0;
}
@@ -248,32 +247,9 @@ public class MonthByWeekAdapter extends SimpleWeeksAdapter {
}
v.setWeekParams(drawingParams, mSelectedDay.timezone);
- sendEventsToView(v);
return v;
}
- private void sendEventsToView(MonthWeekEventsView v) {
- if (mEventDayList.size() == 0) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "No events loaded, did not pass any events to view.");
- }
- v.setEvents(null, null);
- return;
- }
- int viewJulianDay = v.getFirstJulianDay();
- int start = viewJulianDay - mFirstJulianDay;
- int end = start + v.mNumDays;
- if (start < 0 || end > mEventDayList.size()) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Week is outside range of loaded events. viewStart: " + viewJulianDay
- + " eventsStart: " + mFirstJulianDay);
- }
- v.setEvents(null, null);
- return;
- }
- v.setEvents(mEventDayList.subList(start, end), mEvents);
- }
-
@Override
protected void refresh() {
mFirstDayOfWeek = Utils.getFirstDayOfWeek(mContext);
@@ -375,7 +351,6 @@ public class MonthByWeekAdapter extends SimpleWeeksAdapter {
mLongClickedView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
Message message = new Message();
message.obj = day;
- mEventDialogHandler.sendMessage(message);
}
mLongClickedView.clearClickedDay();
mLongClickedView = null;
diff --git a/src/com/android/calendar/month/MonthByWeekFragment.java b/src/com/android/calendar/month/MonthByWeekFragment.java
index 4dd24275..f8a518d3 100644
--- a/src/com/android/calendar/month/MonthByWeekFragment.java
+++ b/src/com/android/calendar/month/MonthByWeekFragment.java
@@ -51,7 +51,6 @@ import com.android.calendar.CalendarController.ViewType;
import com.android.calendar.Event;
import com.android.calendar.R;
import com.android.calendar.Utils;
-import com.android.calendar.event.CreateEventDialogFragment;
import java.util.ArrayList;
import java.util.Calendar;
@@ -64,8 +63,6 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements
private static final String TAG = "MonthFragment";
private static final String TAG_EVENT_DIALOG = "event_dialog";
- private CreateEventDialogFragment mEventDialog;
-
// Selection and selection args for adding event queries
private static final String WHERE_CALENDARS_VISIBLE = Calendars.VISIBLE + "=1";
private static final String INSTANCES_SORT_ORDER = Instances.START_DAY + ","
@@ -99,20 +96,6 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements
private boolean mShowCalendarControls;
private boolean mIsDetached;
- private Handler mEventDialogHandler = new Handler() {
-
- @Override
- public void handleMessage(Message msg) {
- final FragmentManager manager = getFragmentManager();
- if (manager != null) {
- Time day = (Time) msg.obj;
- mEventDialog = new CreateEventDialogFragment(day);
- mEventDialog.show(manager, TAG_EVENT_DIALOG);
- }
- }
- };
-
-
private final Runnable mTZUpdater = new Runnable() {
@Override
public void run() {
@@ -275,7 +258,7 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements
Time.getJulianDay(mSelectedDay.toMillis(true), mSelectedDay.gmtoff));
weekParams.put(SimpleWeeksAdapter.WEEK_PARAMS_DAYS_PER_WEEK, mDaysPerWeek);
if (mAdapter == null) {
- mAdapter = new MonthByWeekAdapter(getActivity(), weekParams, mEventDialogHandler);
+ mAdapter = new MonthByWeekAdapter(getActivity(), weekParams);
mAdapter.registerDataSetObserver(mObserver);
} else {
mAdapter.updateParams(weekParams);
@@ -507,8 +490,5 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements
public boolean onTouch(View v, MotionEvent event) {
mDesiredDay.setToNow();
return false;
- // TODO post a cleanup to push us back onto the grid if something went
- // wrong in a scroll such as the user stopping the view but not
- // scrolling
}
}
diff --git a/src/com/android/calendar/month/MonthListView.java b/src/com/android/calendar/month/MonthListView.java
index 11aa3dac..f2621ccb 100644
--- a/src/com/android/calendar/month/MonthListView.java
+++ b/src/com/android/calendar/month/MonthListView.java
@@ -17,13 +17,8 @@
package com.android.calendar.month;
import android.content.Context;
-import android.graphics.Rect;
-import android.os.SystemClock;
-import android.text.format.Time;
import android.util.AttributeSet;
import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
import android.widget.ListView;
import com.android.calendar.Utils;
@@ -31,167 +26,26 @@ import com.android.calendar.Utils;
public class MonthListView extends ListView {
private static final String TAG = "MonthListView";
- VelocityTracker mTracker;
- private static float mScale = 0;
-
- // These define the behavior of the fling. Below MIN_VELOCITY_FOR_FLING, do the system fling
- // behavior. Between MIN_VELOCITY_FOR_FLING and MULTIPLE_MONTH_VELOCITY_THRESHOLD, do one month
- // fling. Above MULTIPLE_MONTH_VELOCITY_THRESHOLD, do multiple month flings according to the
- // fling strength. When doing multiple month fling, the velocity is reduced by this threshold
- // to prevent moving from one month fling to 4 months and above flings.
- private static int MIN_VELOCITY_FOR_FLING = 1500;
- private static int MULTIPLE_MONTH_VELOCITY_THRESHOLD = 2000;
- private static int FLING_VELOCITY_DIVIDER = 500;
- private static int FLING_TIME = 1000;
-
- // disposable variable used for time calculations
- protected Time mTempTime;
- private long mDownActionTime;
- private final Rect mFirstViewRect = new Rect();
-
- Context mListContext;
-
- // Updates the time zone when it changes
- private final Runnable mTimezoneUpdater = new Runnable() {
- @Override
- public void run() {
- if (mTempTime != null && mListContext != null) {
- mTempTime.timezone =
- Utils.getTimeZone(mListContext, mTimezoneUpdater);
- }
- }
- };
public MonthListView(Context context) {
super(context);
- init(context);
}
public MonthListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- init(context);
}
public MonthListView(Context context, AttributeSet attrs) {
super(context, attrs);
- init(context);
- }
-
- private void init(Context c) {
- mListContext = c;
- mTracker = VelocityTracker.obtain();
- mTempTime = new Time(Utils.getTimeZone(c,mTimezoneUpdater));
- if (mScale == 0) {
- mScale = c.getResources().getDisplayMetrics().density;
- if (mScale != 1) {
- MIN_VELOCITY_FOR_FLING *= mScale;
- MULTIPLE_MONTH_VELOCITY_THRESHOLD *= mScale;
- FLING_VELOCITY_DIVIDER *= mScale;
- }
- }
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
- return processEvent(ev) || super.onTouchEvent(ev);
+ return super.onTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
- return processEvent(ev) || super.onInterceptTouchEvent(ev);
- }
-
- private boolean processEvent (MotionEvent ev) {
- switch (ev.getAction() & MotionEvent.ACTION_MASK) {
- // Since doFling sends a cancel, make sure not to process it.
- case MotionEvent.ACTION_CANCEL:
- return false;
- // Start tracking movement velocity
- case MotionEvent.ACTION_DOWN:
- mTracker.clear();
- mDownActionTime = SystemClock.uptimeMillis();
- break;
- // Accumulate velocity and do a custom fling when above threshold
- case MotionEvent.ACTION_UP:
- mTracker.addMovement(ev);
- mTracker.computeCurrentVelocity(1000); // in pixels per second
- float vel = mTracker.getYVelocity ();
- if (Math.abs(vel) > MIN_VELOCITY_FOR_FLING) {
- doFling(vel);
- return true;
- }
- break;
- default:
- mTracker.addMovement(ev);
- break;
- }
- return false;
- }
-
- // Do a "snap to start of month" fling
- private void doFling(float velocityY) {
-
- // Stop the list-view movement and take over
- MotionEvent cancelEvent = MotionEvent.obtain(mDownActionTime, SystemClock.uptimeMillis(),
- MotionEvent.ACTION_CANCEL, 0, 0, 0);
- onTouchEvent(cancelEvent);
-
- // Below the threshold, fling one month. Above the threshold , fling
- // according to the speed of the fling.
- int monthsToJump;
- if (Math.abs(velocityY) < MULTIPLE_MONTH_VELOCITY_THRESHOLD) {
- if (velocityY < 0) {
- monthsToJump = 1;
- } else {
- // value here is zero and not -1 since by the time the fling is
- // detected the list moved back one month.
- monthsToJump = 0;
- }
- } else {
- if (velocityY < 0) {
- monthsToJump = 1 - (int) ((velocityY + MULTIPLE_MONTH_VELOCITY_THRESHOLD)
- / FLING_VELOCITY_DIVIDER);
- } else {
- monthsToJump = -(int) ((velocityY - MULTIPLE_MONTH_VELOCITY_THRESHOLD)
- / FLING_VELOCITY_DIVIDER);
- }
- }
-
- // Get the day at the top right corner
- int day = getUpperRightJulianDay();
- // Get the day of the first day of the next/previous month
- // (according to scroll direction)
- mTempTime.setJulianDay(day);
- mTempTime.monthDay = 1;
- mTempTime.month += monthsToJump;
- long timeInMillis = mTempTime.normalize(false);
- // Since each view is 7 days, round the target day up to make sure the
- // scroll will be at least one view.
- int scrollToDay = Time.getJulianDay(timeInMillis, mTempTime.gmtoff)
- + ((monthsToJump > 0) ? 6 : 0);
-
- // Since all views have the same height, scroll by pixels instead of
- // "to position".
- // Compensate for the top view offset from the top.
- View firstView = getChildAt(0);
- int firstViewHeight = firstView.getHeight();
- // Get visible part length
- firstView.getLocalVisibleRect(mFirstViewRect);
- int topViewVisiblePart = mFirstViewRect.bottom - mFirstViewRect.top;
- int viewsToFling = (scrollToDay - day) / 7 - ((monthsToJump <= 0) ? 1 : 0);
- int offset = (viewsToFling > 0) ? -(firstViewHeight - topViewVisiblePart
- + SimpleDayPickerFragment.LIST_TOP_OFFSET) : (topViewVisiblePart
- - SimpleDayPickerFragment.LIST_TOP_OFFSET);
- // Fling
- smoothScrollBy(viewsToFling * firstViewHeight + offset, FLING_TIME);
- }
-
- // Returns the julian day of the day in the upper right corner
- private int getUpperRightJulianDay() {
- SimpleWeekView child = (SimpleWeekView) getChildAt(0);
- if (child == null) {
- return -1;
- }
- return child.getFirstJulianDay() + SimpleDayPickerFragment.DAYS_PER_WEEK - 1;
+ return super.onInterceptTouchEvent(ev);
}
}
diff --git a/src/com/android/calendar/month/SimpleDayPickerFragment.java b/src/com/android/calendar/month/SimpleDayPickerFragment.java
index 89f1e005..2efae6a9 100644
--- a/src/com/android/calendar/month/SimpleDayPickerFragment.java
+++ b/src/com/android/calendar/month/SimpleDayPickerFragment.java
@@ -217,9 +217,6 @@ public class SimpleDayPickerFragment extends ListFragment implements OnScrollLis
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (savedInstanceState != null && savedInstanceState.containsKey(KEY_CURRENT_TIME)) {
- goTo(savedInstanceState.getLong(KEY_CURRENT_TIME), false, true, true);
- }
}
@Override
@@ -606,30 +603,6 @@ public class SimpleDayPickerFragment extends ListFragment implements OnScrollLis
if (mNewState == OnScrollListener.SCROLL_STATE_IDLE
&& mPreviousScrollState != OnScrollListener.SCROLL_STATE_IDLE) {
mPreviousScrollState = mNewState;
- // Uncomment the below to add snap to week back
-// int i = 0;
-// View child = mView.getChildAt(i);
-// while (child != null && child.getBottom() <= 0) {
-// child = mView.getChildAt(++i);
-// }
-// if (child == null) {
-// // The view is no longer visible, just return
-// return;
-// }
-// int dist = child.getTop();
-// if (dist < LIST_TOP_OFFSET) {
-// if (Log.isLoggable(TAG, Log.DEBUG)) {
-// Log.d(TAG, "scrolling by " + dist + " up? " + mIsScrollingUp);
-// }
-// int firstPosition = mView.getFirstVisiblePosition();
-// int lastPosition = mView.getLastVisiblePosition();
-// boolean scroll = firstPosition != 0 && lastPosition != mView.getCount() - 1;
-// if (mIsScrollingUp && scroll) {
-// mView.smoothScrollBy(dist, 500);
-// } else if (!mIsScrollingUp && scroll) {
-// mView.smoothScrollBy(child.getHeight() + dist, 500);
-// }
-// }
mAdapter.updateFocusMonth(mCurrentMonthDisplayed);
} else {
mPreviousScrollState = mNewState;
diff --git a/src/com/android/calendar/recurrencepicker/LinearLayoutWithMaxWidth.java b/src/com/android/calendar/recurrencepicker/LinearLayoutWithMaxWidth.java
deleted file mode 100644
index 455a039c..00000000
--- a/src/com/android/calendar/recurrencepicker/LinearLayoutWithMaxWidth.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2013 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.recurrencepicker;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.LinearLayout;
-
-public class LinearLayoutWithMaxWidth extends LinearLayout {
-
- public LinearLayoutWithMaxWidth(Context context) {
- super(context);
- }
-
- public LinearLayoutWithMaxWidth(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public LinearLayoutWithMaxWidth(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- WeekButton.setSuggestedWidth((View.MeasureSpec.getSize(widthMeasureSpec)) / 7);
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-}
diff --git a/src/com/android/calendar/recurrencepicker/RecurrencePickerDialog.java b/src/com/android/calendar/recurrencepicker/RecurrencePickerDialog.java
deleted file mode 100644
index 73591dd9..00000000
--- a/src/com/android/calendar/recurrencepicker/RecurrencePickerDialog.java
+++ /dev/null
@@ -1,1322 +0,0 @@
-/*
- * Copyright (C) 2013 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.recurrencepicker;
-
-import android.app.Activity;
-import android.app.DialogFragment;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.Editable;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-import android.util.Log;
-import android.util.TimeFormatException;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.view.Window;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-import android.widget.Spinner;
-import android.widget.Switch;
-import android.widget.TableLayout;
-import android.widget.TextView;
-import android.widget.Toast;
-import android.widget.ToggleButton;
-
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-import com.android.calendarcommon2.EventRecurrence;
-import com.android.datetimepicker.date.DatePickerDialog;
-
-import java.text.DateFormatSymbols;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-
-public class RecurrencePickerDialog extends DialogFragment implements OnItemSelectedListener,
- OnCheckedChangeListener, OnClickListener,
- android.widget.RadioGroup.OnCheckedChangeListener, DatePickerDialog.OnDateSetListener {
-
- private static final String TAG = "RecurrencePickerDialog";
-
- // in dp's
- private static final int MIN_SCREEN_WIDTH_FOR_SINGLE_ROW_WEEK = 450;
-
- // Update android:maxLength in EditText as needed
- private static final int INTERVAL_MAX = 99;
- private static final int INTERVAL_DEFAULT = 1;
- // Update android:maxLength in EditText as needed
- private static final int COUNT_MAX = 730;
- private static final int COUNT_DEFAULT = 5;
-
- // Special cases in monthlyByNthDayOfWeek
- private static final int FIFTH_WEEK_IN_A_MONTH = 5;
- private static final int LAST_NTH_DAY_OF_WEEK = -1;
-
- private DatePickerDialog mDatePickerDialog;
-
- private class RecurrenceModel implements Parcelable {
-
- // Should match EventRecurrence.DAILY, etc
- static final int FREQ_DAILY = 0;
- static final int FREQ_WEEKLY = 1;
- static final int FREQ_MONTHLY = 2;
- static final int FREQ_YEARLY = 3;
-
- static final int END_NEVER = 0;
- static final int END_BY_DATE = 1;
- static final int END_BY_COUNT = 2;
-
- static final int MONTHLY_BY_DATE = 0;
- static final int MONTHLY_BY_NTH_DAY_OF_WEEK = 1;
-
- static final int STATE_NO_RECURRENCE = 0;
- static final int STATE_RECURRENCE = 1;
-
- int recurrenceState;
-
- /**
- * FREQ: Repeat pattern
- *
- * @see FREQ_DAILY
- * @see FREQ_WEEKLY
- * @see FREQ_MONTHLY
- * @see FREQ_YEARLY
- */
- int freq = FREQ_WEEKLY;
-
- /**
- * INTERVAL: Every n days/weeks/months/years. n >= 1
- */
- int interval = INTERVAL_DEFAULT;
-
- /**
- * UNTIL and COUNT: How does the the event end?
- *
- * @see END_NEVER
- * @see END_BY_DATE
- * @see END_BY_COUNT
- * @see untilDate
- * @see untilCount
- */
- int end;
-
- /**
- * UNTIL: Date of the last recurrence. Used when until == END_BY_DATE
- */
- Time endDate;
-
- /**
- * COUNT: Times to repeat. Use when until == END_BY_COUNT
- */
- int endCount = COUNT_DEFAULT;
-
- /**
- * BYDAY: Days of the week to be repeated. Sun = 0, Mon = 1, etc
- */
- boolean[] weeklyByDayOfWeek = new boolean[7];
-
- /**
- * BYDAY AND BYMONTHDAY: How to repeat monthly events? Same date of the
- * month or Same nth day of week.
- *
- * @see MONTHLY_BY_DATE
- * @see MONTHLY_BY_NTH_DAY_OF_WEEK
- */
- int monthlyRepeat;
-
- /**
- * Day of the month to repeat. Used when monthlyRepeat ==
- * MONTHLY_BY_DATE
- */
- int monthlyByMonthDay;
-
- /**
- * Day of the week to repeat. Used when monthlyRepeat ==
- * MONTHLY_BY_NTH_DAY_OF_WEEK
- */
- int monthlyByDayOfWeek;
-
- /**
- * Nth day of the week to repeat. Used when monthlyRepeat ==
- * MONTHLY_BY_NTH_DAY_OF_WEEK 0=undefined, -1=Last, 1=1st, 2=2nd, ..., 5=5th
- *
- * We support 5th, just to handle backwards capabilities with old bug, but it
- * gets converted to -1 once edited.
- */
- int monthlyByNthDayOfWeek;
-
- /*
- * (generated method)
- */
- @Override
- public String toString() {
- return "Model [freq=" + freq + ", interval=" + interval + ", end=" + end + ", endDate="
- + endDate + ", endCount=" + endCount + ", weeklyByDayOfWeek="
- + Arrays.toString(weeklyByDayOfWeek) + ", monthlyRepeat=" + monthlyRepeat
- + ", monthlyByMonthDay=" + monthlyByMonthDay + ", monthlyByDayOfWeek="
- + monthlyByDayOfWeek + ", monthlyByNthDayOfWeek=" + monthlyByNthDayOfWeek + "]";
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public RecurrenceModel() {
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(freq);
- dest.writeInt(interval);
- dest.writeInt(end);
- dest.writeInt(endDate.year);
- dest.writeInt(endDate.month);
- dest.writeInt(endDate.monthDay);
- dest.writeInt(endCount);
- dest.writeBooleanArray(weeklyByDayOfWeek);
- dest.writeInt(monthlyRepeat);
- dest.writeInt(monthlyByMonthDay);
- dest.writeInt(monthlyByDayOfWeek);
- dest.writeInt(monthlyByNthDayOfWeek);
- dest.writeInt(recurrenceState);
- }
- }
-
- class minMaxTextWatcher implements TextWatcher {
- private int mMin;
- private int mMax;
- private int mDefault;
-
- public minMaxTextWatcher(int min, int defaultInt, int max) {
- mMin = min;
- mMax = max;
- mDefault = defaultInt;
- }
-
- @Override
- public void afterTextChanged(Editable s) {
-
- boolean updated = false;
- int value;
- try {
- value = Integer.parseInt(s.toString());
- } catch (NumberFormatException e) {
- value = mDefault;
- }
-
- if (value < mMin) {
- value = mMin;
- updated = true;
- } else if (value > mMax) {
- updated = true;
- value = mMax;
- }
-
- // Update UI
- if (updated) {
- s.clear();
- s.append(Integer.toString(value));
- }
-
- updateDoneButtonState();
- onChange(value);
- }
-
- /** Override to be called after each key stroke */
- void onChange(int value) {
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
- }
-
- private Resources mResources;
- private EventRecurrence mRecurrence = new EventRecurrence();
- private Time mTime = new Time(); // TODO timezone?
- private RecurrenceModel mModel = new RecurrenceModel();
- private Toast mToast;
-
- private final int[] TIME_DAY_TO_CALENDAR_DAY = new int[] {
- Calendar.SUNDAY,
- Calendar.MONDAY,
- Calendar.TUESDAY,
- Calendar.WEDNESDAY,
- Calendar.THURSDAY,
- Calendar.FRIDAY,
- Calendar.SATURDAY,
- };
-
- // Call mStringBuilder.setLength(0) before formatting any string or else the
- // formatted text will accumulate.
- // private final StringBuilder mStringBuilder = new StringBuilder();
- // private Formatter mFormatter = new Formatter(mStringBuilder);
-
- private View mView;
-
- private Spinner mFreqSpinner;
- private static final int[] mFreqModelToEventRecurrence = {
- EventRecurrence.DAILY,
- EventRecurrence.WEEKLY,
- EventRecurrence.MONTHLY,
- EventRecurrence.YEARLY
- };
-
- public static final String BUNDLE_START_TIME_MILLIS = "bundle_event_start_time";
- public static final String BUNDLE_TIME_ZONE = "bundle_event_time_zone";
- public static final String BUNDLE_RRULE = "bundle_event_rrule";
-
- private static final String BUNDLE_MODEL = "bundle_model";
- private static final String BUNDLE_END_COUNT_HAS_FOCUS = "bundle_end_count_has_focus";
-
- private static final String FRAG_TAG_DATE_PICKER = "tag_date_picker_frag";
-
- private Switch mRepeatSwitch;
-
- private EditText mInterval;
- private TextView mIntervalPreText;
- private TextView mIntervalPostText;
-
- private int mIntervalResId = -1;
-
- private Spinner mEndSpinner;
- private TextView mEndDateTextView;
- private EditText mEndCount;
- private TextView mPostEndCount;
- private boolean mHidePostEndCount;
-
- private ArrayList<CharSequence> mEndSpinnerArray = new ArrayList<CharSequence>(3);
- private EndSpinnerAdapter mEndSpinnerAdapter;
- private String mEndNeverStr;
- private String mEndDateLabel;
- private String mEndCountLabel;
-
- /** Hold toggle buttons in the order per user's first day of week preference */
- private LinearLayout mWeekGroup;
- private LinearLayout mWeekGroup2;
- // Sun = 0
- private ToggleButton[] mWeekByDayButtons = new ToggleButton[7];
- /** A double array of Strings to hold the 7x5 list of possible strings of the form:
- * "on every [Nth] [DAY_OF_WEEK]", e.g. "on every second Monday",
- * where [Nth] can be [first, second, third, fourth, last] */
- private String[][] mMonthRepeatByDayOfWeekStrs;
-
- private LinearLayout mMonthGroup;
- private RadioGroup mMonthRepeatByRadioGroup;
- private RadioButton mRepeatMonthlyByNthDayOfWeek;
- private RadioButton mRepeatMonthlyByNthDayOfMonth;
- private String mMonthRepeatByDayOfWeekStr;
-
- private Button mDone;
-
- private OnRecurrenceSetListener mRecurrenceSetListener;
-
- public RecurrencePickerDialog() {
- }
-
- static public boolean isSupportedMonthlyByNthDayOfWeek(int num) {
- // We only support monthlyByNthDayOfWeek when it is greater then 0 but less then 5.
- // Or if -1 when it is the last monthly day of the week.
- return (num > 0 && num <= FIFTH_WEEK_IN_A_MONTH) || num == LAST_NTH_DAY_OF_WEEK;
- }
-
- static public boolean canHandleRecurrenceRule(EventRecurrence er) {
- switch (er.freq) {
- case EventRecurrence.DAILY:
- case EventRecurrence.MONTHLY:
- case EventRecurrence.YEARLY:
- case EventRecurrence.WEEKLY:
- break;
- default:
- return false;
- }
-
- if (er.count > 0 && !TextUtils.isEmpty(er.until)) {
- return false;
- }
-
- // Weekly: For "repeat by day of week", the day of week to repeat is in
- // er.byday[]
-
- /*
- * Monthly: For "repeat by nth day of week" the day of week to repeat is
- * in er.byday[] and the "nth" is stored in er.bydayNum[]. Currently we
- * can handle only one and only in monthly
- */
- int numOfByDayNum = 0;
- for (int i = 0; i < er.bydayCount; i++) {
- if (isSupportedMonthlyByNthDayOfWeek(er.bydayNum[i])) {
- ++numOfByDayNum;
- }
- }
-
- if (numOfByDayNum > 1) {
- return false;
- }
-
- if (numOfByDayNum > 0 && er.freq != EventRecurrence.MONTHLY) {
- return false;
- }
-
- // The UI only handle repeat by one day of month i.e. not 9th and 10th
- // of every month
- if (er.bymonthdayCount > 1) {
- return false;
- }
-
- if (er.freq == EventRecurrence.MONTHLY) {
- if (er.bydayCount > 1) {
- return false;
- }
- if (er.bydayCount > 0 && er.bymonthdayCount > 0) {
- return false;
- }
- }
-
- return true;
- }
-
- // TODO don't lose data when getting data that our UI can't handle
- static private void copyEventRecurrenceToModel(final EventRecurrence er,
- RecurrenceModel model) {
- // Freq:
- switch (er.freq) {
- case EventRecurrence.DAILY:
- model.freq = RecurrenceModel.FREQ_DAILY;
- break;
- case EventRecurrence.MONTHLY:
- model.freq = RecurrenceModel.FREQ_MONTHLY;
- break;
- case EventRecurrence.YEARLY:
- model.freq = RecurrenceModel.FREQ_YEARLY;
- break;
- case EventRecurrence.WEEKLY:
- model.freq = RecurrenceModel.FREQ_WEEKLY;
- break;
- default:
- throw new IllegalStateException("freq=" + er.freq);
- }
-
- // Interval:
- if (er.interval > 0) {
- model.interval = er.interval;
- }
-
- // End:
- // End by count:
- model.endCount = er.count;
- if (model.endCount > 0) {
- model.end = RecurrenceModel.END_BY_COUNT;
- }
-
- // End by date:
- if (!TextUtils.isEmpty(er.until)) {
- if (model.endDate == null) {
- model.endDate = new Time();
- }
-
- try {
- model.endDate.parse(er.until);
- } catch (TimeFormatException e) {
- model.endDate = null;
- }
-
- // LIMITATION: The UI can only handle END_BY_DATE or END_BY_COUNT
- if (model.end == RecurrenceModel.END_BY_COUNT && model.endDate != null) {
- throw new IllegalStateException("freq=" + er.freq);
- }
-
- model.end = RecurrenceModel.END_BY_DATE;
- }
-
- // Weekly: repeat by day of week or Monthly: repeat by nth day of week
- // in the month
- Arrays.fill(model.weeklyByDayOfWeek, false);
- if (er.bydayCount > 0) {
- int count = 0;
- for (int i = 0; i < er.bydayCount; i++) {
- int dayOfWeek = EventRecurrence.day2TimeDay(er.byday[i]);
- model.weeklyByDayOfWeek[dayOfWeek] = true;
-
- if (model.freq == RecurrenceModel.FREQ_MONTHLY &&
- isSupportedMonthlyByNthDayOfWeek(er.bydayNum[i])) {
- // LIMITATION: Can handle only (one) weekDayNum in nth or last and only
- // when
- // monthly
- model.monthlyByDayOfWeek = dayOfWeek;
- model.monthlyByNthDayOfWeek = er.bydayNum[i];
- model.monthlyRepeat = RecurrenceModel.MONTHLY_BY_NTH_DAY_OF_WEEK;
- count++;
- }
- }
-
- if (model.freq == RecurrenceModel.FREQ_MONTHLY) {
- if (er.bydayCount != 1) {
- // Can't handle 1st Monday and 2nd Wed
- throw new IllegalStateException("Can handle only 1 byDayOfWeek in monthly");
- }
- if (count != 1) {
- throw new IllegalStateException(
- "Didn't specify which nth day of week to repeat for a monthly");
- }
- }
- }
-
- // Monthly by day of month
- if (model.freq == RecurrenceModel.FREQ_MONTHLY) {
- if (er.bymonthdayCount == 1) {
- if (model.monthlyRepeat == RecurrenceModel.MONTHLY_BY_NTH_DAY_OF_WEEK) {
- throw new IllegalStateException(
- "Can handle only by monthday or by nth day of week, not both");
- }
- model.monthlyByMonthDay = er.bymonthday[0];
- model.monthlyRepeat = RecurrenceModel.MONTHLY_BY_DATE;
- } else if (er.bymonthCount > 1) {
- // LIMITATION: Can handle only one month day
- throw new IllegalStateException("Can handle only one bymonthday");
- }
- }
- }
-
- static private void copyModelToEventRecurrence(final RecurrenceModel model,
- EventRecurrence er) {
- if (model.recurrenceState == RecurrenceModel.STATE_NO_RECURRENCE) {
- throw new IllegalStateException("There's no recurrence");
- }
-
- // Freq
- er.freq = mFreqModelToEventRecurrence[model.freq];
-
- // Interval
- if (model.interval <= 1) {
- er.interval = 0;
- } else {
- er.interval = model.interval;
- }
-
- // End
- switch (model.end) {
- case RecurrenceModel.END_BY_DATE:
- if (model.endDate != null) {
- model.endDate.switchTimezone(Time.TIMEZONE_UTC);
- model.endDate.normalize(false);
- er.until = model.endDate.format2445();
- er.count = 0;
- } else {
- throw new IllegalStateException("end = END_BY_DATE but endDate is null");
- }
- break;
- case RecurrenceModel.END_BY_COUNT:
- er.count = model.endCount;
- er.until = null;
- if (er.count <= 0) {
- throw new IllegalStateException("count is " + er.count);
- }
- break;
- default:
- er.count = 0;
- er.until = null;
- break;
- }
-
- // Weekly && monthly repeat patterns
- er.bydayCount = 0;
- er.bymonthdayCount = 0;
-
- switch (model.freq) {
- case RecurrenceModel.FREQ_MONTHLY:
- if (model.monthlyRepeat == RecurrenceModel.MONTHLY_BY_DATE) {
- if (model.monthlyByMonthDay > 0) {
- if (er.bymonthday == null || er.bymonthdayCount < 1) {
- er.bymonthday = new int[1];
- }
- er.bymonthday[0] = model.monthlyByMonthDay;
- er.bymonthdayCount = 1;
- }
- } else if (model.monthlyRepeat == RecurrenceModel.MONTHLY_BY_NTH_DAY_OF_WEEK) {
- if (!isSupportedMonthlyByNthDayOfWeek(model.monthlyByNthDayOfWeek)) {
- throw new IllegalStateException("month repeat by nth week but n is "
- + model.monthlyByNthDayOfWeek);
- }
- int count = 1;
- if (er.bydayCount < count || er.byday == null || er.bydayNum == null) {
- er.byday = new int[count];
- er.bydayNum = new int[count];
- }
- er.bydayCount = count;
- er.byday[0] = EventRecurrence.timeDay2Day(model.monthlyByDayOfWeek);
- er.bydayNum[0] = model.monthlyByNthDayOfWeek;
- }
- break;
- case RecurrenceModel.FREQ_WEEKLY:
- int count = 0;
- for (int i = 0; i < 7; i++) {
- if (model.weeklyByDayOfWeek[i]) {
- count++;
- }
- }
-
- if (er.bydayCount < count || er.byday == null || er.bydayNum == null) {
- er.byday = new int[count];
- er.bydayNum = new int[count];
- }
- er.bydayCount = count;
-
- for (int i = 6; i >= 0; i--) {
- if (model.weeklyByDayOfWeek[i]) {
- er.bydayNum[--count] = 0;
- er.byday[count] = EventRecurrence.timeDay2Day(i);
- }
- }
- break;
- }
-
- if (!canHandleRecurrenceRule(er)) {
- throw new IllegalStateException("UI generated recurrence that it can't handle. ER:"
- + er.toString() + " Model: " + model.toString());
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- mRecurrence.wkst = EventRecurrence.timeDay2Day(Utils.getFirstDayOfWeek(getActivity()));
-
- getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
-
- boolean endCountHasFocus = false;
- if (savedInstanceState != null) {
- RecurrenceModel m = (RecurrenceModel) savedInstanceState.get(BUNDLE_MODEL);
- if (m != null) {
- mModel = m;
- }
- endCountHasFocus = savedInstanceState.getBoolean(BUNDLE_END_COUNT_HAS_FOCUS);
- } else {
- Bundle b = getArguments();
- if (b != null) {
- mTime.set(b.getLong(BUNDLE_START_TIME_MILLIS));
-
- String tz = b.getString(BUNDLE_TIME_ZONE);
- if (!TextUtils.isEmpty(tz)) {
- mTime.timezone = tz;
- }
- mTime.normalize(false);
-
- // Time days of week: Sun=0, Mon=1, etc
- mModel.weeklyByDayOfWeek[mTime.weekDay] = true;
- String rrule = b.getString(BUNDLE_RRULE);
- if (!TextUtils.isEmpty(rrule)) {
- mModel.recurrenceState = RecurrenceModel.STATE_RECURRENCE;
- mRecurrence.parse(rrule);
- copyEventRecurrenceToModel(mRecurrence, mModel);
- // Leave today's day of week as checked by default in weekly view.
- if (mRecurrence.bydayCount == 0) {
- mModel.weeklyByDayOfWeek[mTime.weekDay] = true;
- }
- }
-
- } else {
- mTime.setToNow();
- }
- }
-
- mResources = getResources();
- mView = inflater.inflate(R.layout.recurrencepicker, container, true);
-
- final Activity activity = getActivity();
- final Configuration config = activity.getResources().getConfiguration();
-
- mRepeatSwitch = (Switch) mView.findViewById(R.id.repeat_switch);
- mRepeatSwitch.setChecked(mModel.recurrenceState == RecurrenceModel.STATE_RECURRENCE);
- mRepeatSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
-
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- mModel.recurrenceState = isChecked ? RecurrenceModel.STATE_RECURRENCE
- : RecurrenceModel.STATE_NO_RECURRENCE;
- togglePickerOptions();
- }
- });
-
- mFreqSpinner = (Spinner) mView.findViewById(R.id.freqSpinner);
- mFreqSpinner.setOnItemSelectedListener(this);
- ArrayAdapter<CharSequence> freqAdapter = ArrayAdapter.createFromResource(getActivity(),
- R.array.recurrence_freq, R.layout.recurrencepicker_freq_item);
- freqAdapter.setDropDownViewResource(R.layout.recurrencepicker_freq_item);
- mFreqSpinner.setAdapter(freqAdapter);
-
- mInterval = (EditText) mView.findViewById(R.id.interval);
- mInterval.addTextChangedListener(new minMaxTextWatcher(1, INTERVAL_DEFAULT, INTERVAL_MAX) {
- @Override
- void onChange(int v) {
- if (mIntervalResId != -1 && mInterval.getText().toString().length() > 0) {
- mModel.interval = v;
- updateIntervalText();
- mInterval.requestLayout();
- }
- }
- });
- mIntervalPreText = (TextView) mView.findViewById(R.id.intervalPreText);
- mIntervalPostText = (TextView) mView.findViewById(R.id.intervalPostText);
-
- mEndNeverStr = mResources.getString(R.string.recurrence_end_continously);
- mEndDateLabel = mResources.getString(R.string.recurrence_end_date_label);
- mEndCountLabel = mResources.getString(R.string.recurrence_end_count_label);
-
- mEndSpinnerArray.add(mEndNeverStr);
- mEndSpinnerArray.add(mEndDateLabel);
- mEndSpinnerArray.add(mEndCountLabel);
- mEndSpinner = (Spinner) mView.findViewById(R.id.endSpinner);
- mEndSpinner.setOnItemSelectedListener(this);
- mEndSpinnerAdapter = new EndSpinnerAdapter(getActivity(), mEndSpinnerArray,
- R.layout.recurrencepicker_freq_item, R.layout.recurrencepicker_end_text);
- mEndSpinnerAdapter.setDropDownViewResource(R.layout.recurrencepicker_freq_item);
- mEndSpinner.setAdapter(mEndSpinnerAdapter);
-
- mEndCount = (EditText) mView.findViewById(R.id.endCount);
- mEndCount.addTextChangedListener(new minMaxTextWatcher(1, COUNT_DEFAULT, COUNT_MAX) {
- @Override
- void onChange(int v) {
- if (mModel.endCount != v) {
- mModel.endCount = v;
- updateEndCountText();
- mEndCount.requestLayout();
- }
- }
- });
- mPostEndCount = (TextView) mView.findViewById(R.id.postEndCount);
-
- mEndDateTextView = (TextView) mView.findViewById(R.id.endDate);
- mEndDateTextView.setOnClickListener(this);
- if (mModel.endDate == null) {
- mModel.endDate = new Time(mTime);
- switch (mModel.freq) {
- case RecurrenceModel.FREQ_DAILY:
- case RecurrenceModel.FREQ_WEEKLY:
- mModel.endDate.month += 1;
- break;
- case RecurrenceModel.FREQ_MONTHLY:
- mModel.endDate.month += 3;
- break;
- case RecurrenceModel.FREQ_YEARLY:
- mModel.endDate.year += 3;
- break;
- }
- mModel.endDate.normalize(false);
- }
-
- mWeekGroup = (LinearLayout) mView.findViewById(R.id.weekGroup);
- mWeekGroup2 = (LinearLayout) mView.findViewById(R.id.weekGroup2);
-
- // In Calendar.java day of week order e.g Sun = 1 ... Sat = 7
- String[] dayOfWeekString = new DateFormatSymbols().getWeekdays();
-
- mMonthRepeatByDayOfWeekStrs = new String[7][];
- // from Time.SUNDAY as 0 through Time.SATURDAY as 6
- mMonthRepeatByDayOfWeekStrs[0] = mResources.getStringArray(R.array.repeat_by_nth_sun);
- mMonthRepeatByDayOfWeekStrs[1] = mResources.getStringArray(R.array.repeat_by_nth_mon);
- mMonthRepeatByDayOfWeekStrs[2] = mResources.getStringArray(R.array.repeat_by_nth_tues);
- mMonthRepeatByDayOfWeekStrs[3] = mResources.getStringArray(R.array.repeat_by_nth_wed);
- mMonthRepeatByDayOfWeekStrs[4] = mResources.getStringArray(R.array.repeat_by_nth_thurs);
- mMonthRepeatByDayOfWeekStrs[5] = mResources.getStringArray(R.array.repeat_by_nth_fri);
- mMonthRepeatByDayOfWeekStrs[6] = mResources.getStringArray(R.array.repeat_by_nth_sat);
-
- // In Time.java day of week order e.g. Sun = 0
- int idx = Utils.getFirstDayOfWeek(getActivity());
-
- // In Calendar.java day of week order e.g Sun = 1 ... Sat = 7
- dayOfWeekString = new DateFormatSymbols().getShortWeekdays();
-
- int numOfButtonsInRow1;
- int numOfButtonsInRow2;
-
- if (mResources.getConfiguration().screenWidthDp > MIN_SCREEN_WIDTH_FOR_SINGLE_ROW_WEEK) {
- numOfButtonsInRow1 = 7;
- numOfButtonsInRow2 = 0;
- mWeekGroup2.setVisibility(View.GONE);
- mWeekGroup2.getChildAt(3).setVisibility(View.GONE);
- } else {
- numOfButtonsInRow1 = 4;
- numOfButtonsInRow2 = 3;
-
- mWeekGroup2.setVisibility(View.VISIBLE);
- // Set rightmost button on the second row invisible so it takes up
- // space and everything centers properly
- mWeekGroup2.getChildAt(3).setVisibility(View.INVISIBLE);
- }
-
- /* First row */
- for (int i = 0; i < 7; i++) {
- if (i >= numOfButtonsInRow1) {
- mWeekGroup.getChildAt(i).setVisibility(View.GONE);
- continue;
- }
-
- mWeekByDayButtons[idx] = (ToggleButton) mWeekGroup.getChildAt(i);
- mWeekByDayButtons[idx].setTextOff(dayOfWeekString[TIME_DAY_TO_CALENDAR_DAY[idx]]);
- mWeekByDayButtons[idx].setTextOn(dayOfWeekString[TIME_DAY_TO_CALENDAR_DAY[idx]]);
- mWeekByDayButtons[idx].setOnCheckedChangeListener(this);
-
- if (++idx >= 7) {
- idx = 0;
- }
- }
-
- /* 2nd Row */
- for (int i = 0; i < 3; i++) {
- if (i >= numOfButtonsInRow2) {
- mWeekGroup2.getChildAt(i).setVisibility(View.GONE);
- continue;
- }
- mWeekByDayButtons[idx] = (ToggleButton) mWeekGroup2.getChildAt(i);
- mWeekByDayButtons[idx].setTextOff(dayOfWeekString[TIME_DAY_TO_CALENDAR_DAY[idx]]);
- mWeekByDayButtons[idx].setTextOn(dayOfWeekString[TIME_DAY_TO_CALENDAR_DAY[idx]]);
- mWeekByDayButtons[idx].setOnCheckedChangeListener(this);
-
- if (++idx >= 7) {
- idx = 0;
- }
- }
-
- mMonthGroup = (LinearLayout) mView.findViewById(R.id.monthGroup);
- mMonthRepeatByRadioGroup = (RadioGroup) mView.findViewById(R.id.monthGroup);
- mMonthRepeatByRadioGroup.setOnCheckedChangeListener(this);
- mRepeatMonthlyByNthDayOfWeek = (RadioButton) mView
- .findViewById(R.id.repeatMonthlyByNthDayOfTheWeek);
- mRepeatMonthlyByNthDayOfMonth = (RadioButton) mView
- .findViewById(R.id.repeatMonthlyByNthDayOfMonth);
-
- mDone = (Button) mView.findViewById(R.id.done);
- mDone.setOnClickListener(this);
-
- togglePickerOptions();
- updateDialog();
- if (endCountHasFocus) {
- mEndCount.requestFocus();
- }
- return mView;
- }
-
- private void togglePickerOptions() {
- if (mModel.recurrenceState == RecurrenceModel.STATE_NO_RECURRENCE) {
- mFreqSpinner.setEnabled(false);
- mEndSpinner.setEnabled(false);
- mIntervalPreText.setEnabled(false);
- mInterval.setEnabled(false);
- mIntervalPostText.setEnabled(false);
- mMonthRepeatByRadioGroup.setEnabled(false);
- mEndCount.setEnabled(false);
- mPostEndCount.setEnabled(false);
- mEndDateTextView.setEnabled(false);
- mRepeatMonthlyByNthDayOfWeek.setEnabled(false);
- mRepeatMonthlyByNthDayOfMonth.setEnabled(false);
- for (Button button : mWeekByDayButtons) {
- button.setEnabled(false);
- }
- } else {
- mView.findViewById(R.id.options).setEnabled(true);
- mFreqSpinner.setEnabled(true);
- mEndSpinner.setEnabled(true);
- mIntervalPreText.setEnabled(true);
- mInterval.setEnabled(true);
- mIntervalPostText.setEnabled(true);
- mMonthRepeatByRadioGroup.setEnabled(true);
- mEndCount.setEnabled(true);
- mPostEndCount.setEnabled(true);
- mEndDateTextView.setEnabled(true);
- mRepeatMonthlyByNthDayOfWeek.setEnabled(true);
- mRepeatMonthlyByNthDayOfMonth.setEnabled(true);
- for (Button button : mWeekByDayButtons) {
- button.setEnabled(true);
- }
- }
- updateDoneButtonState();
- }
-
- private void updateDoneButtonState() {
- if (mModel.recurrenceState == RecurrenceModel.STATE_NO_RECURRENCE) {
- mDone.setEnabled(true);
- return;
- }
-
- if (mInterval.getText().toString().length() == 0) {
- mDone.setEnabled(false);
- return;
- }
-
- if (mEndCount.getVisibility() == View.VISIBLE &&
- mEndCount.getText().toString().length() == 0) {
- mDone.setEnabled(false);
- return;
- }
-
- if (mModel.freq == RecurrenceModel.FREQ_WEEKLY) {
- for (CompoundButton b : mWeekByDayButtons) {
- if (b.isChecked()) {
- mDone.setEnabled(true);
- return;
- }
- }
- mDone.setEnabled(false);
- return;
- }
-
- mDone.setEnabled(true);
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putParcelable(BUNDLE_MODEL, mModel);
- if (mEndCount.hasFocus()) {
- outState.putBoolean(BUNDLE_END_COUNT_HAS_FOCUS, true);
- }
- }
-
- public void updateDialog() {
- // Interval
- // Checking before setting because this causes infinite recursion
- // in afterTextWatcher
- final String intervalStr = Integer.toString(mModel.interval);
- if (!intervalStr.equals(mInterval.getText().toString())) {
- mInterval.setText(intervalStr);
- }
-
- mFreqSpinner.setSelection(mModel.freq);
- mWeekGroup.setVisibility(mModel.freq == RecurrenceModel.FREQ_WEEKLY ? View.VISIBLE : View.GONE);
- mWeekGroup2.setVisibility(mModel.freq == RecurrenceModel.FREQ_WEEKLY ? View.VISIBLE : View.GONE);
- mMonthGroup.setVisibility(mModel.freq == RecurrenceModel.FREQ_MONTHLY ? View.VISIBLE : View.GONE);
-
- switch (mModel.freq) {
- case RecurrenceModel.FREQ_DAILY:
- mIntervalResId = R.plurals.recurrence_interval_daily;
- break;
-
- case RecurrenceModel.FREQ_WEEKLY:
- mIntervalResId = R.plurals.recurrence_interval_weekly;
- for (int i = 0; i < 7; i++) {
- mWeekByDayButtons[i].setChecked(mModel.weeklyByDayOfWeek[i]);
- }
- break;
-
- case RecurrenceModel.FREQ_MONTHLY:
- mIntervalResId = R.plurals.recurrence_interval_monthly;
-
- if (mModel.monthlyRepeat == RecurrenceModel.MONTHLY_BY_DATE) {
- mMonthRepeatByRadioGroup.check(R.id.repeatMonthlyByNthDayOfMonth);
- } else if (mModel.monthlyRepeat == RecurrenceModel.MONTHLY_BY_NTH_DAY_OF_WEEK) {
- mMonthRepeatByRadioGroup.check(R.id.repeatMonthlyByNthDayOfTheWeek);
- }
-
- if (mMonthRepeatByDayOfWeekStr == null) {
- if (mModel.monthlyByNthDayOfWeek == 0) {
- mModel.monthlyByNthDayOfWeek = (mTime.monthDay + 6) / 7;
- // Since not all months have 5 weeks, we convert 5th NthDayOfWeek to
- // -1 for last monthly day of the week
- if (mModel.monthlyByNthDayOfWeek >= FIFTH_WEEK_IN_A_MONTH) {
- mModel.monthlyByNthDayOfWeek = LAST_NTH_DAY_OF_WEEK;
- }
- mModel.monthlyByDayOfWeek = mTime.weekDay;
- }
-
- String[] monthlyByNthDayOfWeekStrs =
- mMonthRepeatByDayOfWeekStrs[mModel.monthlyByDayOfWeek];
-
- // TODO(psliwowski): Find a better way handle -1 indexes
- int msgIndex = mModel.monthlyByNthDayOfWeek < 0 ? FIFTH_WEEK_IN_A_MONTH :
- mModel.monthlyByNthDayOfWeek;
- mMonthRepeatByDayOfWeekStr =
- monthlyByNthDayOfWeekStrs[msgIndex - 1];
- mRepeatMonthlyByNthDayOfWeek.setText(mMonthRepeatByDayOfWeekStr);
- }
- break;
-
- case RecurrenceModel.FREQ_YEARLY:
- mIntervalResId = R.plurals.recurrence_interval_yearly;
- break;
- }
- updateIntervalText();
- updateDoneButtonState();
-
- mEndSpinner.setSelection(mModel.end);
- if (mModel.end == RecurrenceModel.END_BY_DATE) {
- final String dateStr = DateUtils.formatDateTime(getActivity(),
- mModel.endDate.toMillis(false), DateUtils.FORMAT_NUMERIC_DATE);
- mEndDateTextView.setText(dateStr);
- } else {
- if (mModel.end == RecurrenceModel.END_BY_COUNT) {
- // Checking before setting because this causes infinite
- // recursion
- // in afterTextWatcher
- final String countStr = Integer.toString(mModel.endCount);
- if (!countStr.equals(mEndCount.getText().toString())) {
- mEndCount.setText(countStr);
- }
- }
- }
- }
-
- /**
- * @param endDateString
- */
- private void setEndSpinnerEndDateStr(final String endDateString) {
- mEndSpinnerArray.set(1, endDateString);
- mEndSpinnerAdapter.notifyDataSetChanged();
- }
-
- private void doToast() {
- Log.e(TAG, "Model = " + mModel.toString());
- String rrule;
- if (mModel.recurrenceState == RecurrenceModel.STATE_NO_RECURRENCE) {
- rrule = "Not repeating";
- } else {
- copyModelToEventRecurrence(mModel, mRecurrence);
- rrule = mRecurrence.toString();
- }
-
- if (mToast != null) {
- mToast.cancel();
- }
- mToast = Toast.makeText(getActivity(), rrule,
- Toast.LENGTH_LONG);
- mToast.show();
- }
-
- // TODO Test and update for Right-to-Left
- private void updateIntervalText() {
- if (mIntervalResId == -1) {
- return;
- }
-
- final String INTERVAL_COUNT_MARKER = "%d";
- String intervalString = mResources.getQuantityString(mIntervalResId, mModel.interval);
- int markerStart = intervalString.indexOf(INTERVAL_COUNT_MARKER);
-
- if (markerStart != -1) {
- int postTextStart = markerStart + INTERVAL_COUNT_MARKER.length();
- mIntervalPostText.setText(intervalString.substring(postTextStart,
- intervalString.length()).trim());
- mIntervalPreText.setText(intervalString.substring(0, markerStart).trim());
- }
- }
-
- /**
- * Update the "Repeat for N events" end option with the proper string values
- * based on the value that has been entered for N.
- */
- private void updateEndCountText() {
- final String END_COUNT_MARKER = "%d";
- String endString = mResources.getQuantityString(R.plurals.recurrence_end_count,
- mModel.endCount);
- int markerStart = endString.indexOf(END_COUNT_MARKER);
-
- if (markerStart != -1) {
- if (markerStart == 0) {
- Log.e(TAG, "No text to put in to recurrence's end spinner.");
- } else {
- int postTextStart = markerStart + END_COUNT_MARKER.length();
- mPostEndCount.setText(endString.substring(postTextStart,
- endString.length()).trim());
- }
- }
- }
-
- // Implements OnItemSelectedListener interface
- // Freq spinner
- // End spinner
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- if (parent == mFreqSpinner) {
- mModel.freq = position;
- } else if (parent == mEndSpinner) {
- switch (position) {
- case RecurrenceModel.END_NEVER:
- mModel.end = RecurrenceModel.END_NEVER;
- break;
- case RecurrenceModel.END_BY_DATE:
- mModel.end = RecurrenceModel.END_BY_DATE;
- break;
- case RecurrenceModel.END_BY_COUNT:
- mModel.end = RecurrenceModel.END_BY_COUNT;
-
- if (mModel.endCount <= 1) {
- mModel.endCount = 1;
- } else if (mModel.endCount > COUNT_MAX) {
- mModel.endCount = COUNT_MAX;
- }
- updateEndCountText();
- break;
- }
- mEndCount.setVisibility(mModel.end == RecurrenceModel.END_BY_COUNT ? View.VISIBLE
- : View.GONE);
- mEndDateTextView.setVisibility(mModel.end == RecurrenceModel.END_BY_DATE ? View.VISIBLE
- : View.GONE);
- mPostEndCount.setVisibility(
- mModel.end == RecurrenceModel.END_BY_COUNT && !mHidePostEndCount?
- View.VISIBLE : View.GONE);
-
- }
- updateDialog();
- }
-
- // Implements OnItemSelectedListener interface
- @Override
- public void onNothingSelected(AdapterView<?> arg0) {
- }
-
- @Override
- public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) {
- if (mModel.endDate == null) {
- mModel.endDate = new Time(mTime.timezone);
- mModel.endDate.hour = mModel.endDate.minute = mModel.endDate.second = 0;
- }
- mModel.endDate.year = year;
- mModel.endDate.month = monthOfYear;
- mModel.endDate.monthDay = dayOfMonth;
- mModel.endDate.normalize(false);
- updateDialog();
- }
-
- // Implements OnCheckedChangeListener interface
- // Week repeat by day of week
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- int itemIdx = -1;
- for (int i = 0; i < 7; i++) {
- if (itemIdx == -1 && buttonView == mWeekByDayButtons[i]) {
- itemIdx = i;
- mModel.weeklyByDayOfWeek[i] = isChecked;
- }
- }
- updateDialog();
- }
-
- // Implements android.widget.RadioGroup.OnCheckedChangeListener interface
- // Month repeat by radio buttons
- @Override
- public void onCheckedChanged(RadioGroup group, int checkedId) {
- if (checkedId == R.id.repeatMonthlyByNthDayOfMonth) {
- mModel.monthlyRepeat = RecurrenceModel.MONTHLY_BY_DATE;
- } else if (checkedId == R.id.repeatMonthlyByNthDayOfTheWeek) {
- mModel.monthlyRepeat = RecurrenceModel.MONTHLY_BY_NTH_DAY_OF_WEEK;
- }
- updateDialog();
- }
-
- // Implements OnClickListener interface
- // EndDate button
- // Done button
- @Override
- public void onClick(View v) {
- if (mEndDateTextView == v) {
- if (mDatePickerDialog != null) {
- mDatePickerDialog.dismiss();
- }
- mDatePickerDialog = DatePickerDialog.newInstance(this, mModel.endDate.year,
- mModel.endDate.month, mModel.endDate.monthDay);
- mDatePickerDialog.setFirstDayOfWeek(Utils.getFirstDayOfWeekAsCalendar(getActivity()));
- mDatePickerDialog.setYearRange(Utils.YEAR_MIN, Utils.YEAR_MAX);
- mDatePickerDialog.show(getFragmentManager(), FRAG_TAG_DATE_PICKER);
- } else if (mDone == v) {
- String rrule;
- if (mModel.recurrenceState == RecurrenceModel.STATE_NO_RECURRENCE) {
- rrule = null;
- } else {
- copyModelToEventRecurrence(mModel, mRecurrence);
- rrule = mRecurrence.toString();
- }
- mRecurrenceSetListener.onRecurrenceSet(rrule);
- dismiss();
- }
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- mDatePickerDialog = (DatePickerDialog) getFragmentManager()
- .findFragmentByTag(FRAG_TAG_DATE_PICKER);
- if (mDatePickerDialog != null) {
- mDatePickerDialog.setOnDateSetListener(this);
- }
- }
-
- public interface OnRecurrenceSetListener {
- void onRecurrenceSet(String rrule);
- }
-
- public void setOnRecurrenceSetListener(OnRecurrenceSetListener l) {
- mRecurrenceSetListener = l;
- }
-
- private class EndSpinnerAdapter extends ArrayAdapter<CharSequence> {
- final String END_DATE_MARKER = "%s";
- final String END_COUNT_MARKER = "%d";
-
- private LayoutInflater mInflater;
- private int mItemResourceId;
- private int mTextResourceId;
- private ArrayList<CharSequence> mStrings;
- private String mEndDateString;
- private boolean mUseFormStrings;
-
- /**
- * @param context
- * @param textViewResourceId
- * @param objects
- */
- public EndSpinnerAdapter(Context context, ArrayList<CharSequence> strings,
- int itemResourceId, int textResourceId) {
- super(context, itemResourceId, strings);
- mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mItemResourceId = itemResourceId;
- mTextResourceId = textResourceId;
- mStrings = strings;
- mEndDateString = getResources().getString(R.string.recurrence_end_date);
-
- // If either date or count strings don't translate well, such that we aren't assured
- // to have some text available to be placed in the spinner, then we'll have to use
- // the more form-like versions of both strings instead.
- int markerStart = mEndDateString.indexOf(END_DATE_MARKER);
- if (markerStart <= 0) {
- // The date string does not have any text before the "%s" so we'll have to use the
- // more form-like strings instead.
- mUseFormStrings = true;
- } else {
- String countEndStr = getResources().getQuantityString(
- R.plurals.recurrence_end_count, 1);
- markerStart = countEndStr.indexOf(END_COUNT_MARKER);
- if (markerStart <= 0) {
- // The count string does not have any text before the "%d" so we'll have to use
- // the more form-like strings instead.
- mUseFormStrings = true;
- }
- }
-
- if (mUseFormStrings) {
- // We'll have to set the layout for the spinner to be weight=0 so it doesn't
- // take up too much space.
- mEndSpinner.setLayoutParams(
- new TableLayout.LayoutParams(0, LayoutParams.WRAP_CONTENT, 1f));
- }
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View v;
- // Check if we can recycle the view
- if (convertView == null) {
- v = mInflater.inflate(mTextResourceId, parent, false);
- } else {
- v = convertView;
- }
-
- TextView item = (TextView) v.findViewById(R.id.spinner_item);
- int markerStart;
- switch (position) {
- case RecurrenceModel.END_NEVER:
- item.setText(mStrings.get(RecurrenceModel.END_NEVER));
- break;
- case RecurrenceModel.END_BY_DATE:
- markerStart = mEndDateString.indexOf(END_DATE_MARKER);
-
- if (markerStart != -1) {
- if (mUseFormStrings || markerStart == 0) {
- // If we get here, the translation of "Until" doesn't work correctly,
- // so we'll just set the whole "Until a date" string.
- item.setText(mEndDateLabel);
- } else {
- item.setText(mEndDateString.substring(0, markerStart).trim());
- }
- }
- break;
- case RecurrenceModel.END_BY_COUNT:
- String endString = mResources.getQuantityString(R.plurals.recurrence_end_count,
- mModel.endCount);
- markerStart = endString.indexOf(END_COUNT_MARKER);
-
- if (markerStart != -1) {
- if (mUseFormStrings || markerStart == 0) {
- // If we get here, the translation of "For" doesn't work correctly,
- // so we'll just set the whole "For a number of events" string.
- item.setText(mEndCountLabel);
- // Also, we'll hide the " events" that would have been at the end.
- mPostEndCount.setVisibility(View.GONE);
- // Use this flag so the onItemSelected knows whether to show it later.
- mHidePostEndCount = true;
- } else {
- int postTextStart = markerStart + END_COUNT_MARKER.length();
- mPostEndCount.setText(endString.substring(postTextStart,
- endString.length()).trim());
- // In case it's a recycled view that wasn't visible.
- if (mModel.end == RecurrenceModel.END_BY_COUNT) {
- mPostEndCount.setVisibility(View.VISIBLE);
- }
- if (endString.charAt(markerStart - 1) == ' ') {
- markerStart--;
- }
- item.setText(endString.substring(0, markerStart).trim());
- }
- }
- break;
- default:
- v = null;
- break;
- }
-
- return v;
- }
-
- @Override
- public View getDropDownView(int position, View convertView, ViewGroup parent) {
- View v;
- // Check if we can recycle the view
- if (convertView == null) {
- v = mInflater.inflate(mItemResourceId, parent, false);
- } else {
- v = convertView;
- }
-
- TextView item = (TextView) v.findViewById(R.id.spinner_item);
- item.setText(mStrings.get(position));
-
- return v;
- }
- }
-}
diff --git a/src/com/android/calendar/recurrencepicker/WeekButton.java b/src/com/android/calendar/recurrencepicker/WeekButton.java
deleted file mode 100644
index 5a8171eb..00000000
--- a/src/com/android/calendar/recurrencepicker/WeekButton.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2013 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.recurrencepicker;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-
-public class WeekButton extends android.widget.ToggleButton {
-
- private static int mWidth;
-
- public WeekButton(Context context) {
- super(context);
- }
-
- public WeekButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public WeekButton(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- public static void setSuggestedWidth(int w) {
- mWidth = w;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int h = getMeasuredHeight();
- int w = getMeasuredWidth();
- if (h > 0 && w > 0) {
- if (w < h) {
- if (View.MeasureSpec.getMode(getMeasuredHeightAndState()) != MeasureSpec.EXACTLY) {
- h = w;
- }
- } else if (h < w) {
- if (View.MeasureSpec.getMode(getMeasuredWidthAndState()) != MeasureSpec.EXACTLY) {
- w = h;
- }
- }
- }
- setMeasuredDimension(w, h);
- }
-}
diff --git a/src/com/android/calendar/selectcalendars/CalendarColorCache.java b/src/com/android/calendar/selectcalendars/CalendarColorCache.java
deleted file mode 100644
index 0f9d14e2..00000000
--- a/src/com/android/calendar/selectcalendars/CalendarColorCache.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2013 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.selectcalendars;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.provider.CalendarContract.Colors;
-
-import com.android.calendar.AsyncQueryService;
-
-import java.util.HashSet;
-
-/**
- * CalendarColorCache queries the provider and stores the account identifiers (name and type)
- * of the accounts which contain optional calendar colors, and thus should allow for the
- * user to choose calendar colors.
- */
-public class CalendarColorCache {
-
- private HashSet<String> mCache = new HashSet<String>();
-
- private static final String SEPARATOR = "::";
-
- private AsyncQueryService mService;
- private OnCalendarColorsLoadedListener mListener;
-
- private StringBuffer mStringBuffer = new StringBuffer();
-
- private static String[] PROJECTION = new String[] {Colors.ACCOUNT_NAME, Colors.ACCOUNT_TYPE };
-
- /**
- * Interface which provides callback after provider query of calendar colors.
- */
- public interface OnCalendarColorsLoadedListener {
-
- /**
- * Callback after the set of accounts with additional calendar colors are loaded.
- */
- void onCalendarColorsLoaded();
- }
-
- public CalendarColorCache(Context context, OnCalendarColorsLoadedListener listener) {
- mListener = listener;
- mService = new AsyncQueryService(context) {
-
- @Override
- public void onQueryComplete(int token, Object cookie, Cursor c) {
- if (c == null) {
- return;
- }
- if (c.moveToFirst()) {
- clear();
- do {
- insert(c.getString(0), c.getString(1));
- } while (c.moveToNext());
- mListener.onCalendarColorsLoaded();
- }
- if (c != null) {
- c.close();
- }
- }
- };
- mService.startQuery(0, null, Colors.CONTENT_URI, PROJECTION,
- Colors.COLOR_TYPE + "=" + Colors.TYPE_CALENDAR, null, null);
- }
-
- /**
- * Inserts a specified account into the set.
- */
- private void insert(String accountName, String accountType) {
- mCache.add(generateKey(accountName, accountType));
- }
-
- /**
- * Does a set lookup to determine if a specified account has more optional calendar colors.
- */
- public boolean hasColors(String accountName, String accountType) {
- return mCache.contains(generateKey(accountName, accountType));
- }
-
- /**
- * Clears the cached set.
- */
- private void clear() {
- mCache.clear();
- }
-
- /**
- * Generates a single key based on account name and account type for map lookup/insertion.
- */
- private String generateKey(String accountName, String accountType) {
- mStringBuffer.setLength(0);
- return mStringBuffer.append(accountName).append(SEPARATOR).append(accountType).toString();
- }
-}
diff --git a/src/com/android/calendar/selectcalendars/CalendarColorSquare.java b/src/com/android/calendar/selectcalendars/CalendarColorSquare.java
deleted file mode 100644
index 3631e11c..00000000
--- a/src/com/android/calendar/selectcalendars/CalendarColorSquare.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2013 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.selectcalendars;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.widget.QuickContactBadge;
-
-import com.android.calendar.CalendarColorPickerDialog;
-import com.android.calendar.R;
-import com.android.colorpicker.ColorStateDrawable;
-
-/**
- * The color square used as an entry point to launching the {@link CalendarColorPickerDialog}.
- */
-public class CalendarColorSquare extends QuickContactBadge {
-
- public CalendarColorSquare(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public CalendarColorSquare(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- @Override
- public void setBackgroundColor(int color) {
- Drawable[] colorDrawable = new Drawable[] {
- getContext().getResources().getDrawable(R.drawable.calendar_color_square) };
- setImageDrawable(new ColorStateDrawable(colorDrawable, color));
- }
-}
diff --git a/src/com/android/calendar/selectcalendars/SelectCalendarsSimpleAdapter.java b/src/com/android/calendar/selectcalendars/SelectCalendarsSimpleAdapter.java
deleted file mode 100644
index 6a75d2b3..00000000
--- a/src/com/android/calendar/selectcalendars/SelectCalendarsSimpleAdapter.java
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.calendar.selectcalendars;
-
-import android.app.FragmentManager;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.provider.CalendarContract.Calendars;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.TouchDelegate;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.widget.BaseAdapter;
-import android.widget.CheckBox;
-import android.widget.ListAdapter;
-import android.widget.TextView;
-
-import com.android.calendar.CalendarColorPickerDialog;
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-import com.android.calendar.selectcalendars.CalendarColorCache.OnCalendarColorsLoadedListener;
-
-public class SelectCalendarsSimpleAdapter extends BaseAdapter implements ListAdapter,
- OnCalendarColorsLoadedListener {
- private static final String TAG = "SelectCalendarsAdapter";
- private static final String COLOR_PICKER_DIALOG_TAG = "ColorPickerDialog";
-
- private static int BOTTOM_ITEM_HEIGHT = 64;
- private static int NORMAL_ITEM_HEIGHT = 48;
-
- private static final int IS_SELECTED = 1 << 0;
- private static final int IS_TOP = 1 << 1;
- private static final int IS_BOTTOM = 1 << 2;
- private static final int IS_BELOW_SELECTED = 1 << 3;
-
- private CalendarColorPickerDialog mColorPickerDialog;
-
- private LayoutInflater mInflater;
- Resources mRes;
- private int mLayout;
- private int mOrientation;
- private CalendarRow[] mData;
- private Cursor mCursor;
- private int mRowCount = 0;
-
- private FragmentManager mFragmentManager;
- private boolean mIsTablet;
- private int mColorViewTouchAreaIncrease;
-
- private int mIdColumn;
- private int mNameColumn;
- private int mColorColumn;
- private int mVisibleColumn;
- private int mOwnerAccountColumn;
- private int mAccountNameColumn;
- private int mAccountTypeColumn;
- private static float mScale = 0;
- private int mColorCalendarVisible;
- private int mColorCalendarHidden;
- private int mColorCalendarSecondaryVisible;
- private int mColorCalendarSecondaryHidden;
-
- private CalendarColorCache mCache;
-
- private class CalendarRow {
- long id;
- String displayName;
- String ownerAccount;
- String accountName;
- String accountType;
- int color;
- boolean selected;
- }
-
- public SelectCalendarsSimpleAdapter(Context context, int layout, Cursor c, FragmentManager fm) {
- super();
- mLayout = layout;
- mOrientation = context.getResources().getConfiguration().orientation;
- initData(c);
- mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mRes = context.getResources();
- mColorCalendarVisible = mRes.getColor(R.color.calendar_visible);
- mColorCalendarHidden = mRes.getColor(R.color.calendar_hidden);
- mColorCalendarSecondaryVisible = mRes.getColor(R.color.calendar_secondary_visible);
- mColorCalendarSecondaryHidden = mRes.getColor(R.color.calendar_secondary_hidden);
-
- if (mScale == 0) {
- mScale = mRes.getDisplayMetrics().density;
- BOTTOM_ITEM_HEIGHT *= mScale;
- NORMAL_ITEM_HEIGHT *= mScale;
- }
-
- mCache = new CalendarColorCache(context, this);
-
- mFragmentManager = fm;
- mColorPickerDialog = (CalendarColorPickerDialog)
- fm.findFragmentByTag(COLOR_PICKER_DIALOG_TAG);
- mIsTablet = Utils.getConfigBool(context, R.bool.tablet_config);
- mColorViewTouchAreaIncrease = context.getResources()
- .getDimensionPixelSize(R.dimen.color_view_touch_area_increase);
- }
-
- private static class TabletCalendarItemBackgrounds {
- static private int[] mBackgrounds = null;
-
- /**
- * Sets up the background drawables for the calendars list
- *
- * @param res The context's resources
- */
- static int[] getBackgrounds() {
- // Not thread safe. Ok if called only from main thread
- if (mBackgrounds != null) {
- return mBackgrounds;
- }
-
- mBackgrounds = new int[16];
-
- mBackgrounds[0] = R.drawable.calname_unselected;
-
- mBackgrounds[IS_SELECTED] = R.drawable.calname_select_underunselected;
-
- mBackgrounds[IS_SELECTED | IS_BOTTOM] =
- R.drawable.calname_bottom_select_underunselected;
-
- mBackgrounds[IS_SELECTED | IS_BOTTOM | IS_BELOW_SELECTED] =
- R.drawable.calname_bottom_select_underselect;
- mBackgrounds[IS_SELECTED | IS_TOP | IS_BOTTOM | IS_BELOW_SELECTED] = mBackgrounds[
- IS_SELECTED | IS_BOTTOM | IS_BELOW_SELECTED];
- mBackgrounds[IS_SELECTED | IS_TOP | IS_BOTTOM] = mBackgrounds[IS_SELECTED | IS_BOTTOM
- | IS_BELOW_SELECTED];
-
- mBackgrounds[IS_SELECTED | IS_BELOW_SELECTED] = R.drawable.calname_select_underselect;
- mBackgrounds[IS_SELECTED | IS_TOP | IS_BELOW_SELECTED] = mBackgrounds[IS_SELECTED
- | IS_BELOW_SELECTED];
- mBackgrounds[IS_SELECTED | IS_TOP] = mBackgrounds[IS_SELECTED | IS_BELOW_SELECTED];
-
- mBackgrounds[IS_BOTTOM] = R.drawable.calname_bottom_unselected;
-
- mBackgrounds[IS_BOTTOM | IS_BELOW_SELECTED] =
- R.drawable.calname_bottom_unselected_underselect;
- mBackgrounds[IS_TOP | IS_BOTTOM | IS_BELOW_SELECTED] = mBackgrounds[IS_BOTTOM
- | IS_BELOW_SELECTED];
- mBackgrounds[IS_TOP | IS_BOTTOM] = mBackgrounds[IS_BOTTOM | IS_BELOW_SELECTED];
-
- mBackgrounds[IS_BELOW_SELECTED] = R.drawable.calname_unselected_underselect;
- mBackgrounds[IS_TOP | IS_BELOW_SELECTED] = mBackgrounds[IS_BELOW_SELECTED];
- mBackgrounds[IS_TOP] = mBackgrounds[IS_BELOW_SELECTED];
- return mBackgrounds;
- }
- }
-
- private void initData(Cursor c) {
- if (mCursor != null && c != mCursor) {
- mCursor.close();
- }
- if (c == null) {
- mCursor = c;
- mRowCount = 0;
- mData = null;
- return;
- }
- // TODO create a broadcast listener for ACTION_PROVIDER_CHANGED to update the cursor
- mCursor = c;
- mIdColumn = c.getColumnIndexOrThrow(Calendars._ID);
- mNameColumn = c.getColumnIndexOrThrow(Calendars.CALENDAR_DISPLAY_NAME);
- mColorColumn = c.getColumnIndexOrThrow(Calendars.CALENDAR_COLOR);
- mVisibleColumn = c.getColumnIndexOrThrow(Calendars.VISIBLE);
- mOwnerAccountColumn = c.getColumnIndexOrThrow(Calendars.OWNER_ACCOUNT);
- mAccountNameColumn = c.getColumnIndexOrThrow(Calendars.ACCOUNT_NAME);
- mAccountTypeColumn = c.getColumnIndexOrThrow(Calendars.ACCOUNT_TYPE);
-
- mRowCount = c.getCount();
- mData = new CalendarRow[(c.getCount())];
- c.moveToPosition(-1);
- int p = 0;
- while (c.moveToNext()) {
- mData[p] = new CalendarRow();
- mData[p].id = c.getLong(mIdColumn);
- mData[p].displayName = c.getString(mNameColumn);
- mData[p].color = c.getInt(mColorColumn);
- mData[p].selected = c.getInt(mVisibleColumn) != 0;
- mData[p].ownerAccount = c.getString(mOwnerAccountColumn);
- mData[p].accountName = c.getString(mAccountNameColumn);
- mData[p].accountType = c.getString(mAccountTypeColumn);
- p++;
- }
- }
-
- public void changeCursor(Cursor c) {
- initData(c);
- notifyDataSetChanged();
- }
-
- @Override
- public View getView(final int position, View convertView, ViewGroup parent) {
- if (position >= mRowCount) {
- return null;
- }
- String name = mData[position].displayName;
- boolean selected = mData[position].selected;
-
- int color = Utils.getDisplayColorFromColor(mData[position].color);
- View view;
- if (convertView == null) {
- view = mInflater.inflate(mLayout, parent, false);
- final View delegate = view.findViewById(R.id.color);
- final View delegateParent = (View) delegate.getParent();
- delegateParent.post(new Runnable() {
-
- @Override
- public void run() {
- final Rect r = new Rect();
- delegate.getHitRect(r);
- r.top -= mColorViewTouchAreaIncrease;
- r.bottom += mColorViewTouchAreaIncrease;
- r.left -= mColorViewTouchAreaIncrease;
- r.right += mColorViewTouchAreaIncrease;
- delegateParent.setTouchDelegate(new TouchDelegate(r, delegate));
- }
- });
- } else {
- view = convertView;
- }
-
- TextView calendarName = (TextView) view.findViewById(R.id.calendar);
- calendarName.setText(name);
-
- View colorView = view.findViewById(R.id.color);
- colorView.setBackgroundColor(color);
- colorView.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // Purely for sanity check--view should be disabled if account has no more colors
- if (!hasMoreColors(position)) {
- return;
- }
-
- if (mColorPickerDialog == null) {
- mColorPickerDialog = CalendarColorPickerDialog.newInstance(mData[position].id,
- mIsTablet);
- } else {
- mColorPickerDialog.setCalendarId(mData[position].id);
- }
- mFragmentManager.executePendingTransactions();
- if (!mColorPickerDialog.isAdded()) {
- mColorPickerDialog.show(mFragmentManager, COLOR_PICKER_DIALOG_TAG);
- }
- }
- });
-
- int textColor;
- if (selected) {
- textColor = mColorCalendarVisible;
- } else {
- textColor = mColorCalendarHidden;
- }
- calendarName.setTextColor(textColor);
-
- CheckBox syncCheckBox = (CheckBox) view.findViewById(R.id.sync);
- if (syncCheckBox != null) {
-
- // Full screen layout
- syncCheckBox.setChecked(selected);
-
- colorView.setEnabled(hasMoreColors(position));
- LayoutParams layoutParam = calendarName.getLayoutParams();
- TextView secondaryText = (TextView) view.findViewById(R.id.status);
- if (!TextUtils.isEmpty(mData[position].ownerAccount)
- && !mData[position].ownerAccount.equals(name)
- && !mData[position].ownerAccount.endsWith("calendar.google.com")) {
- int secondaryColor;
- if (selected) {
- secondaryColor = mColorCalendarSecondaryVisible;
- } else {
- secondaryColor = mColorCalendarSecondaryHidden;
- }
- secondaryText.setText(mData[position].ownerAccount);
- secondaryText.setTextColor(secondaryColor);
- secondaryText.setVisibility(View.VISIBLE);
- layoutParam.height = LayoutParams.WRAP_CONTENT;
- } else {
- secondaryText.setVisibility(View.GONE);
- layoutParam.height = LayoutParams.MATCH_PARENT;
- }
-
- calendarName.setLayoutParams(layoutParam);
-
- } else {
- // Tablet layout
- view.findViewById(R.id.color).setEnabled(selected && hasMoreColors(position));
- view.setBackgroundDrawable(getBackground(position, selected));
- ViewGroup.LayoutParams newParams = view.getLayoutParams();
- if (position == mData.length - 1) {
- newParams.height = BOTTOM_ITEM_HEIGHT;
- } else {
- newParams.height = NORMAL_ITEM_HEIGHT;
- }
- view.setLayoutParams(newParams);
- CheckBox visibleCheckBox = (CheckBox) view.findViewById(R.id.visible_check_box);
- if (visibleCheckBox != null) {
- visibleCheckBox.setChecked(selected);
- }
- }
- view.invalidate();
- return view;
- }
-
- private boolean hasMoreColors(int position) {
- return mCache.hasColors(mData[position].accountName, mData[position].accountType);
- }
-
- /**
- * @param position position of the calendar item
- * @param selected whether it is selected or not
- * @return the drawable to use for this view
- */
- protected Drawable getBackground(int position, boolean selected) {
- int bg;
- bg = selected ? IS_SELECTED : 0;
- bg |= (position == 0 && mOrientation == Configuration.ORIENTATION_LANDSCAPE) ? IS_TOP : 0;
- bg |= position == mData.length - 1 ? IS_BOTTOM : 0;
- bg |= (position > 0 && mData[position - 1].selected) ? IS_BELOW_SELECTED : 0;
- return mRes.getDrawable(TabletCalendarItemBackgrounds.getBackgrounds()[bg]);
- }
-
- @Override
- public int getCount() {
- return mRowCount;
- }
-
- @Override
- public Object getItem(int position) {
- if (position >= mRowCount) {
- return null;
- }
- CalendarRow item = mData[position];
- return item;
- }
-
- @Override
- public long getItemId(int position) {
- if (position >= mRowCount) {
- return 0;
- }
- return mData[position].id;
- }
-
- public void setVisible(int position, int visible) {
- mData[position].selected = visible != 0;
- notifyDataSetChanged();
- }
-
- public int getVisible(int position) {
- return mData[position].selected ? 1 : 0;
- }
-
- @Override
- public boolean hasStableIds() {
- return true;
- }
-
- @Override
- public void onCalendarColorsLoaded() {
- notifyDataSetChanged();
- }
-}
diff --git a/src/com/android/calendar/selectcalendars/SelectCalendarsSyncAdapter.java b/src/com/android/calendar/selectcalendars/SelectCalendarsSyncAdapter.java
deleted file mode 100644
index 6e740bbf..00000000
--- a/src/com/android/calendar/selectcalendars/SelectCalendarsSyncAdapter.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.calendar.selectcalendars;
-
-import android.app.FragmentManager;
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.Rect;
-import android.graphics.drawable.shapes.RectShape;
-import android.provider.CalendarContract.Calendars;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.TouchDelegate;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.CheckBox;
-import android.widget.ListAdapter;
-import android.widget.TextView;
-
-import com.android.calendar.CalendarColorPickerDialog;
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-import com.android.calendar.selectcalendars.CalendarColorCache.OnCalendarColorsLoadedListener;
-
-import java.util.HashMap;
-
-public class SelectCalendarsSyncAdapter extends BaseAdapter
- implements ListAdapter, AdapterView.OnItemClickListener, OnCalendarColorsLoadedListener {
- private static final String TAG = "SelCalsAdapter";
- private static final String COLOR_PICKER_DIALOG_TAG = "ColorPickerDialog";
-
- private static int COLOR_CHIP_SIZE = 30;
- private RectShape r = new RectShape();
-
- private CalendarColorPickerDialog mColorPickerDialog;
- private CalendarColorCache mCache;
-
- private LayoutInflater mInflater;
- private static final int LAYOUT = R.layout.calendar_sync_item;
- private CalendarRow[] mData;
- private HashMap<Long, CalendarRow> mChanges = new HashMap<Long, CalendarRow>();
- private int mRowCount = 0;
-
- private int mIdColumn;
- private int mNameColumn;
- private int mColorColumn;
- private int mSyncedColumn;
- private int mAccountNameColumn;
- private int mAccountTypeColumn;
-
- private boolean mIsTablet;
- private FragmentManager mFragmentManager;
- private int mColorViewTouchAreaIncrease;
-
-
- private final String mSyncedString;
- private final String mNotSyncedString;
-
- public class CalendarRow {
- long id;
- String displayName;
- int color;
- boolean synced;
- boolean originalSynced;
- String accountName;
- String accountType;
- }
-
- public SelectCalendarsSyncAdapter(Context context, Cursor c, FragmentManager manager) {
- super();
- initData(c);
- mCache = new CalendarColorCache(context, this);
- mFragmentManager = manager;
- mColorPickerDialog = (CalendarColorPickerDialog)
- manager.findFragmentByTag(COLOR_PICKER_DIALOG_TAG);
- mColorViewTouchAreaIncrease = context.getResources()
- .getDimensionPixelSize(R.dimen.color_view_touch_area_increase);
- mIsTablet = Utils.getConfigBool(context, R.bool.tablet_config);
- mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- COLOR_CHIP_SIZE *= context.getResources().getDisplayMetrics().density;
- r.resize(COLOR_CHIP_SIZE, COLOR_CHIP_SIZE);
- Resources res = context.getResources();
- mSyncedString = res.getString(R.string.synced);
- mNotSyncedString = res.getString(R.string.not_synced);
- }
-
- private void initData(Cursor c) {
- if (c == null) {
- mRowCount = 0;
- mData = null;
- return;
- }
-
- mIdColumn = c.getColumnIndexOrThrow(Calendars._ID);
- mNameColumn = c.getColumnIndexOrThrow(Calendars.CALENDAR_DISPLAY_NAME);
- mColorColumn = c.getColumnIndexOrThrow(Calendars.CALENDAR_COLOR);
- mSyncedColumn = c.getColumnIndexOrThrow(Calendars.SYNC_EVENTS);
- mAccountNameColumn = c.getColumnIndexOrThrow(Calendars.ACCOUNT_NAME);
- mAccountTypeColumn = c.getColumnIndexOrThrow(Calendars.ACCOUNT_TYPE);
-
- mRowCount = c.getCount();
- mData = new CalendarRow[mRowCount];
- c.moveToPosition(-1);
- int p = 0;
- while (c.moveToNext()) {
- long id = c.getLong(mIdColumn);
- mData[p] = new CalendarRow();
- mData[p].id = id;
- mData[p].displayName = c.getString(mNameColumn);
- mData[p].color = c.getInt(mColorColumn);
- mData[p].originalSynced = c.getInt(mSyncedColumn) != 0;
- mData[p].accountName = c.getString(mAccountNameColumn);
- mData[p].accountType = c.getString(mAccountTypeColumn);
- if (mChanges.containsKey(id)) {
- mData[p].synced = mChanges.get(id).synced;
- } else {
- mData[p].synced = mData[p].originalSynced;
- }
- p++;
- }
- }
-
- public void changeCursor(Cursor c) {
- initData(c);
- notifyDataSetChanged();
- }
-
- @Override
- public View getView(final int position, View convertView, ViewGroup parent) {
- if (position >= mRowCount) {
- return null;
- }
- String name = mData[position].displayName;
- boolean selected = mData[position].synced;
- int color = Utils.getDisplayColorFromColor(mData[position].color);
- View view;
- if (convertView == null) {
- view = mInflater.inflate(LAYOUT, parent, false);
- final View delegate = view.findViewById(R.id.color);
- final View delegateParent = (View) delegate.getParent();
- delegateParent.post(new Runnable() {
-
- @Override
- public void run() {
- final Rect r = new Rect();
- delegate.getHitRect(r);
- r.top -= mColorViewTouchAreaIncrease;
- r.bottom += mColorViewTouchAreaIncrease;
- r.left -= mColorViewTouchAreaIncrease;
- r.right += mColorViewTouchAreaIncrease;
- delegateParent.setTouchDelegate(new TouchDelegate(r, delegate));
- }
- });
- } else {
- view = convertView;
- }
-
- view.setTag(mData[position]);
-
- CheckBox cb = (CheckBox) view.findViewById(R.id.sync);
- cb.setChecked(selected);
-
- if (selected) {
- setText(view, R.id.status, mSyncedString);
- } else {
- setText(view, R.id.status, mNotSyncedString);
- }
-
- View colorView = view.findViewById(R.id.color);
- colorView.setEnabled(hasMoreColors(position));
- colorView.setBackgroundColor(color);
- colorView.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- // Purely for sanity check--view should be disabled if account has no more colors
- if (!hasMoreColors(position)) {
- return;
- }
-
- if (mColorPickerDialog == null) {
- mColorPickerDialog = CalendarColorPickerDialog.newInstance(mData[position].id,
- mIsTablet);
- } else {
- mColorPickerDialog.setCalendarId(mData[position].id);
- }
- mFragmentManager.executePendingTransactions();
- if (!mColorPickerDialog.isAdded()) {
- mColorPickerDialog.show(mFragmentManager, COLOR_PICKER_DIALOG_TAG);
- }
- }
- });
-
- setText(view, R.id.calendar, name);
- return view;
- }
-
- private boolean hasMoreColors(int position) {
- return mCache.hasColors(mData[position].accountName, mData[position].accountType);
- }
-
- private static void setText(View view, int id, String text) {
- if (TextUtils.isEmpty(text)) {
- return;
- }
- TextView textView = (TextView) view.findViewById(id);
- textView.setText(text);
- }
-
- @Override
- public int getCount() {
- return mRowCount;
- }
-
- @Override
- public Object getItem(int position) {
- if (position >= mRowCount) {
- return null;
- }
- CalendarRow item = mData[position];
- return item;
- }
-
- @Override
- public long getItemId(int position) {
- if (position >= mRowCount) {
- return 0;
- }
- return mData[position].id;
- }
-
- @Override
- public boolean hasStableIds() {
- return true;
- }
-
- public int getSynced(int position) {
- return mData[position].synced ? 1 : 0;
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- CalendarRow row = (CalendarRow) view.getTag();
- row.synced = !row.synced;
-
- String status;
- if (row.synced) {
- status = mSyncedString;
- } else {
- status = mNotSyncedString;
- }
- setText(view, R.id.status, status);
-
- CheckBox cb = (CheckBox) view.findViewById(R.id.sync);
- cb.setChecked(row.synced);
-
- // There is some data loss in long -> int, but we should never see it in
- // practice regarding calendar ids.
- mChanges.put(row.id, row);
- }
-
- public HashMap<Long, CalendarRow> getChanges() {
- return mChanges;
- }
-
- @Override
- public void onCalendarColorsLoaded() {
- notifyDataSetChanged();
- }
-}
diff --git a/src/com/android/calendar/selectcalendars/SelectCalendarsSyncFragment.java b/src/com/android/calendar/selectcalendars/SelectCalendarsSyncFragment.java
deleted file mode 100644
index abdd50d2..00000000
--- a/src/com/android/calendar/selectcalendars/SelectCalendarsSyncFragment.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.calendar.selectcalendars;
-
-import android.accounts.Account;
-import android.app.Activity;
-import android.app.ListFragment;
-import android.app.LoaderManager;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.CursorLoader;
-import android.content.Intent;
-import android.content.Loader;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.provider.CalendarContract;
-import android.provider.CalendarContract.Calendars;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.ListAdapter;
-import android.widget.TextView;
-
-import com.android.calendar.AsyncQueryService;
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-import com.android.calendar.selectcalendars.SelectCalendarsSyncAdapter.CalendarRow;
-
-import java.util.HashMap;
-
-public class SelectCalendarsSyncFragment extends ListFragment
- implements View.OnClickListener, LoaderManager.LoaderCallbacks<Cursor> {
-
- private static final String TAG = "SelectCalendarSync";
-
- private static final String COLLATE_NOCASE = " COLLATE NOCASE";
- private static final String SELECTION = Calendars.ACCOUNT_NAME + "=? AND "
- + Calendars.ACCOUNT_TYPE + "=?";
- // is primary lets us sort the user's main calendar to the top of the list
- private static final String IS_PRIMARY = "\"primary\"";
- private static final String SORT_ORDER = IS_PRIMARY + " DESC," + Calendars.CALENDAR_DISPLAY_NAME
- + COLLATE_NOCASE;
-
- private static final String[] PROJECTION = new String[] {
- Calendars._ID,
- Calendars.CALENDAR_DISPLAY_NAME,
- Calendars.CALENDAR_COLOR,
- Calendars.SYNC_EVENTS,
- Calendars.ACCOUNT_NAME,
- Calendars.ACCOUNT_TYPE,
- "(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + IS_PRIMARY, };
-
- private TextView mSyncStatus;
- private Button mAccountsButton;
- private Account mAccount;
- private final String[] mArgs = new String[2];
- private AsyncQueryService mService;
- private Handler mHandler = new Handler();
- private ContentObserver mCalendarsObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- // We don't need our own sync changes to trigger refreshes.
- if (!selfChange) {
- getLoaderManager().initLoader(0, null, SelectCalendarsSyncFragment.this);
- }
- }
- };
-
- public SelectCalendarsSyncFragment() {
- }
-
- public SelectCalendarsSyncFragment(Bundle bundle) {
- mAccount = new Account(bundle.getString(Calendars.ACCOUNT_NAME),
- bundle.getString(Calendars.ACCOUNT_TYPE));
- }
-
- @Override
- public View onCreateView(
- LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View v = inflater.inflate(R.layout.account_calendars, null);
- mSyncStatus = (TextView) v.findViewById(R.id.account_status);
- mSyncStatus.setVisibility(View.GONE);
-
- mAccountsButton = (Button) v.findViewById(R.id.sync_settings);
- mAccountsButton.setVisibility(View.GONE);
- mAccountsButton.setOnClickListener(this);
-
- return v;
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- // Give some text to display if there is no data. In a real
- // application this would come from a resource.
- setEmptyText(getActivity().getText(R.string.no_syncable_calendars));
- // Prepare the loader. Either re-connect with an existing one,
- // or start a new one.
- getLoaderManager().initLoader(0, null, this);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- if (!ContentResolver.getMasterSyncAutomatically()
- || !ContentResolver.getSyncAutomatically(mAccount, CalendarContract.AUTHORITY)) {
- Resources res = getActivity().getResources();
- mSyncStatus.setText(res.getString(R.string.acct_not_synced));
- mSyncStatus.setVisibility(View.VISIBLE);
- mAccountsButton.setText(res.getString(R.string.accounts));
- mAccountsButton.setVisibility(View.VISIBLE);
- } else {
- mSyncStatus.setVisibility(View.GONE);
- mAccountsButton.setVisibility(View.GONE);
-
- // Start a background sync to get the list of calendars from the server.
- Utils.startCalendarMetafeedSync(mAccount);
- getActivity().getContentResolver().registerContentObserver(
- Calendars.CONTENT_URI, true, mCalendarsObserver);
- }
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- mService = new AsyncQueryService(activity);
-
- Bundle bundle = getArguments();
- if (bundle != null && bundle.containsKey(Calendars.ACCOUNT_NAME)
- && bundle.containsKey(Calendars.ACCOUNT_TYPE)) {
- mAccount = new Account(bundle.getString(Calendars.ACCOUNT_NAME),
- bundle.getString(Calendars.ACCOUNT_TYPE));
- }
- }
-
- @Override
- public void onPause() {
- final ListAdapter listAdapter = getListAdapter();
- if (listAdapter != null) {
- HashMap<Long, CalendarRow> changes = ((SelectCalendarsSyncAdapter) listAdapter)
- .getChanges();
- if (changes != null && changes.size() > 0) {
- for (CalendarRow row : changes.values()) {
- if (row.synced == row.originalSynced) {
- continue;
- }
- long id = row.id;
- mService.cancelOperation((int) id);
- // Use the full long id in case it makes a difference
- Uri uri = ContentUris.withAppendedId(Calendars.CONTENT_URI, row.id);
- ContentValues values = new ContentValues();
- // Toggle the current setting
- int synced = row.synced ? 1 : 0;
- values.put(Calendars.SYNC_EVENTS, synced);
- values.put(Calendars.VISIBLE, synced);
- mService.startUpdate((int) id, null, uri, values, null, null, 0);
- }
- changes.clear();
- }
- }
- getActivity().getContentResolver().unregisterContentObserver(mCalendarsObserver);
- super.onPause();
- }
-
- @Override
- public Loader<Cursor> onCreateLoader(int id, Bundle args) {
- mArgs[0] = mAccount.name;
- mArgs[1] = mAccount.type;
- return new CursorLoader(
- getActivity(), Calendars.CONTENT_URI, PROJECTION, SELECTION, mArgs, SORT_ORDER);
- }
-
- @Override
- public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- SelectCalendarsSyncAdapter adapter = (SelectCalendarsSyncAdapter) getListAdapter();
- if (adapter == null) {
- adapter = new SelectCalendarsSyncAdapter(getActivity(), data, getFragmentManager());
- setListAdapter(adapter);
- } else {
- adapter.changeCursor(data);
- }
- getListView().setOnItemClickListener(adapter);
- }
-
- public void onLoaderReset(Loader<Cursor> loader) {
- setListAdapter(null);
- }
-
- // Called when the Accounts button is pressed. Takes the user to the
- // Accounts and Sync settings page.
- @Override
- public void onClick(View v) {
- Intent intent = new Intent();
- intent.setAction("android.settings.SYNC_SETTINGS");
- getActivity().startActivity(intent);
- }
-}
diff --git a/src/com/android/calendar/selectcalendars/SelectSyncedCalendarsMultiAccountActivity.java b/src/com/android/calendar/selectcalendars/SelectSyncedCalendarsMultiAccountActivity.java
deleted file mode 100644
index 84fc67df..00000000
--- a/src/com/android/calendar/selectcalendars/SelectSyncedCalendarsMultiAccountActivity.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2011 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.selectcalendars;
-
-import android.app.ActionBar;
-import android.app.ExpandableListActivity;
-import android.content.AsyncQueryHandler;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.os.Bundle;
-import android.provider.CalendarContract.Calendars;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.ExpandableListView;
-
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-
-public class SelectSyncedCalendarsMultiAccountActivity extends ExpandableListActivity
- implements View.OnClickListener {
-
- private static final String TAG = "Calendar";
- private static final String EXPANDED_KEY = "is_expanded";
- private static final String ACCOUNT_UNIQUE_KEY = "ACCOUNT_KEY";
- private MatrixCursor mAccountsCursor = null;
- private ExpandableListView mList;
- private SelectSyncedCalendarsMultiAccountAdapter mAdapter;
- private static final String[] PROJECTION = new String[] {
- Calendars._ID,
- Calendars.ACCOUNT_TYPE,
- Calendars.ACCOUNT_NAME,
- Calendars.ACCOUNT_TYPE + " || " + Calendars.ACCOUNT_NAME + " AS " +
- ACCOUNT_UNIQUE_KEY,
- };
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- setContentView(R.layout.select_calendars_multi_accounts_fragment);
- mList = getExpandableListView();
- mList.setEmptyView(findViewById(R.id.loading));
- // Start a background sync to get the list of calendars from the server.
- Utils.startCalendarMetafeedSync(null);
-
- findViewById(R.id.btn_done).setOnClickListener(this);
- findViewById(R.id.btn_discard).setOnClickListener(this);
- }
-
- @Override
- public void onClick(View view) {
- if (view.getId() == R.id.btn_done) {
- if (mAdapter != null) {
- mAdapter.doSaveAction();
- }
- finish();
- } else if (view.getId() == R.id.btn_discard) {
- finish();
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- if (mAdapter != null) {
- mAdapter.startRefreshStopDelay();
- }
- new AsyncQueryHandler(getContentResolver()) {
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- mAccountsCursor = Utils.matrixCursorFromCursor(cursor);
-
- mAdapter = new SelectSyncedCalendarsMultiAccountAdapter(
- findViewById(R.id.calendars).getContext(), mAccountsCursor,
- SelectSyncedCalendarsMultiAccountActivity.this);
- mList.setAdapter(mAdapter);
-
- // TODO initialize from sharepref
- int count = mList.getCount();
- for(int i = 0; i < count; i++) {
- mList.expandGroup(i);
- }
- }
- }.startQuery(0, null, Calendars.CONTENT_URI, PROJECTION,
- "1) GROUP BY (" + ACCOUNT_UNIQUE_KEY, //Cheap hack to make WHERE a GROUP BY query
- null /* selectionArgs */,
- Calendars.ACCOUNT_NAME /*sort order*/);
- //TODO change to something that supports group by queries.
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- if (mAdapter != null) {
- mAdapter.cancelRefreshStopDelay();
- }
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- if (mAdapter != null) {
- mAdapter.closeChildrenCursors();
- }
- if (mAccountsCursor != null && !mAccountsCursor.isClosed()) {
- mAccountsCursor.close();
- }
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- boolean[] isExpanded;
- mList = getExpandableListView();
- if(mList != null) {
- int count = mList.getCount();
- isExpanded = new boolean[count];
- for(int i = 0; i < count; i++) {
- isExpanded[i] = mList.isGroupExpanded(i);
- }
- } else {
- isExpanded = null;
- }
- outState.putBooleanArray(EXPANDED_KEY, isExpanded);
- //TODO Store this to preferences instead so it remains on restart
- }
-
- @Override
- protected void onRestoreInstanceState(Bundle state) {
- super.onRestoreInstanceState(state);
- mList = getExpandableListView();
- boolean[] isExpanded = state.getBooleanArray(EXPANDED_KEY);
- if(mList != null && isExpanded != null && mList.getCount() >= isExpanded.length) {
- for(int i = 0; i < isExpanded.length; i++) {
- if(isExpanded[i] && !mList.isGroupExpanded(i)) {
- mList.expandGroup(i);
- } else if(!isExpanded[i] && mList.isGroupExpanded(i)){
- mList.collapseGroup(i);
- }
- }
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getActionBar()
- .setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- Utils.returnToCalendarHome(this);
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-}
diff --git a/src/com/android/calendar/selectcalendars/SelectSyncedCalendarsMultiAccountAdapter.java b/src/com/android/calendar/selectcalendars/SelectSyncedCalendarsMultiAccountAdapter.java
deleted file mode 100644
index 58cdbdb8..00000000
--- a/src/com/android/calendar/selectcalendars/SelectSyncedCalendarsMultiAccountAdapter.java
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * Copyright (C) 2011 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.selectcalendars;
-
-import android.accounts.AccountManager;
-import android.accounts.AuthenticatorDescription;
-import android.app.FragmentManager;
-import android.content.AsyncQueryHandler;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.graphics.Rect;
-import android.net.Uri;
-import android.provider.CalendarContract.Calendars;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.TouchDelegate;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.CheckBox;
-import android.widget.CursorTreeAdapter;
-import android.widget.TextView;
-
-import com.android.calendar.CalendarColorPickerDialog;
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-import com.android.calendar.selectcalendars.CalendarColorCache.OnCalendarColorsLoadedListener;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-public class SelectSyncedCalendarsMultiAccountAdapter extends CursorTreeAdapter implements
- View.OnClickListener, OnCalendarColorsLoadedListener {
-
- private static final String TAG = "Calendar";
- private static final String COLOR_PICKER_DIALOG_TAG = "ColorPickerDialog";
-
- private static final String IS_PRIMARY = "\"primary\"";
- private static final String CALENDARS_ORDERBY = IS_PRIMARY + " DESC,"
- + Calendars.CALENDAR_DISPLAY_NAME + " COLLATE NOCASE";
- private static final String ACCOUNT_SELECTION = Calendars.ACCOUNT_NAME + "=?"
- + " AND " + Calendars.ACCOUNT_TYPE + "=?";
-
- private final LayoutInflater mInflater;
- private final ContentResolver mResolver;
- private final SelectSyncedCalendarsMultiAccountActivity mActivity;
- private final FragmentManager mFragmentManager;
- private final boolean mIsTablet;
- private CalendarColorPickerDialog mColorPickerDialog;
- private final View mView;
- private final static Runnable mStopRefreshing = new Runnable() {
- @Override
- public void run() {
- mRefresh = false;
- }
- };
- private Map<String, AuthenticatorDescription> mTypeToAuthDescription
- = new HashMap<String, AuthenticatorDescription>();
- protected AuthenticatorDescription[] mAuthDescs;
-
- // These track changes to the synced state of calendars
- private Map<Long, Boolean> mCalendarChanges
- = new HashMap<Long, Boolean>();
- private Map<Long, Boolean> mCalendarInitialStates
- = new HashMap<Long, Boolean>();
-
- // Flag for when the cursors have all been closed to ensure no race condition with queries.
- private boolean mClosedCursorsFlag;
-
- // This is for keeping MatrixCursor copies so that we can requery in the background.
- private Map<String, Cursor> mChildrenCursors
- = new HashMap<String, Cursor>();
-
- private AsyncCalendarsUpdater mCalendarsUpdater;
- // This is to keep our update tokens separate from other tokens. Since we cancel old updates
- // when a new update comes in, we'd like to leave a token space that won't be canceled.
- private static final int MIN_UPDATE_TOKEN = 1000;
- private static int mUpdateToken = MIN_UPDATE_TOKEN;
- // How long to wait between requeries of the calendars to see if anything has changed.
- private static final int REFRESH_DELAY = 5000;
- // How long to keep refreshing for
- private static final int REFRESH_DURATION = 60000;
- private static boolean mRefresh = true;
-
- private static String mSyncedText;
- private static String mNotSyncedText;
-
- // This is to keep track of whether or not multiple calendars have the same display name
- private static HashMap<String, Boolean> mIsDuplicateName = new HashMap<String, Boolean>();
-
- private int mColorViewTouchAreaIncrease;
-
- private static final String[] PROJECTION = new String[] {
- Calendars._ID,
- Calendars.ACCOUNT_NAME,
- Calendars.OWNER_ACCOUNT,
- Calendars.CALENDAR_DISPLAY_NAME,
- Calendars.CALENDAR_COLOR,
- Calendars.VISIBLE,
- Calendars.SYNC_EVENTS,
- "(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + IS_PRIMARY,
- Calendars.ACCOUNT_TYPE
- };
- //Keep these in sync with the projection
- private static final int ID_COLUMN = 0;
- private static final int ACCOUNT_COLUMN = 1;
- private static final int OWNER_COLUMN = 2;
- private static final int NAME_COLUMN = 3;
- private static final int COLOR_COLUMN = 4;
- private static final int SELECTED_COLUMN = 5;
- private static final int SYNCED_COLUMN = 6;
- private static final int PRIMARY_COLUMN = 7;
- private static final int ACCOUNT_TYPE_COLUMN = 8;
-
- private static final int TAG_ID_CALENDAR_ID = R.id.calendar;
- private static final int TAG_ID_SYNC_CHECKBOX = R.id.sync;
-
- private CalendarColorCache mCache;
-
- private class AsyncCalendarsUpdater extends AsyncQueryHandler {
-
- public AsyncCalendarsUpdater(ContentResolver cr) {
- super(cr);
- }
-
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- if(cursor == null) {
- return;
- }
- synchronized(mChildrenCursors) {
- if (mClosedCursorsFlag || (mActivity != null && mActivity.isFinishing())) {
- cursor.close();
- return;
- }
- }
-
- Cursor currentCursor = mChildrenCursors.get(cookie);
- // Check if the new cursor has the same content as our old cursor
- if (currentCursor != null) {
- if (Utils.compareCursors(currentCursor, cursor)) {
- cursor.close();
- return;
- }
- }
- // If not then make a new matrix cursor for our Map
- MatrixCursor newCursor = Utils.matrixCursorFromCursor(cursor);
- cursor.close();
- // And update our list of duplicated names
- Utils.checkForDuplicateNames(mIsDuplicateName, newCursor, NAME_COLUMN);
-
- mChildrenCursors.put((String)cookie, newCursor);
- try {
- setChildrenCursor(token, newCursor);
- } catch (NullPointerException e) {
- Log.w(TAG, "Adapter expired, try again on the next query: " + e);
- }
- // Clean up our old cursor if we had one. We have to do this after setting the new
- // cursor so that our view doesn't throw on an invalid cursor.
- if (currentCursor != null) {
- currentCursor.close();
- }
- }
- }
-
- /**
- * Method for changing the sync state when a calendar's button is pressed.
- *
- * This gets called when the CheckBox for a calendar is clicked. It toggles
- * the sync state for the associated calendar and saves a change of state to
- * a hashmap. It also compares against the original value and removes any
- * changes from the hashmap if this is back at its initial state.
- */
- @Override
- public void onClick(View v) {
- long id = (Long) v.getTag(TAG_ID_CALENDAR_ID);
- boolean newState;
- boolean initialState = mCalendarInitialStates.get(id);
- if (mCalendarChanges.containsKey(id)) {
- // Negate to reflect the click
- newState = !mCalendarChanges.get(id);
- } else {
- // Negate to reflect the click
- newState = !initialState;
- }
-
- if (newState == initialState) {
- mCalendarChanges.remove(id);
- } else {
- mCalendarChanges.put(id, newState);
- }
-
- ((CheckBox) v.getTag(TAG_ID_SYNC_CHECKBOX)).setChecked(newState);
- setText(v, R.id.status, newState ? mSyncedText : mNotSyncedText);
- }
-
- public SelectSyncedCalendarsMultiAccountAdapter(Context context, Cursor acctsCursor,
- SelectSyncedCalendarsMultiAccountActivity act) {
- super(acctsCursor, context);
- mSyncedText = context.getString(R.string.synced);
- mNotSyncedText = context.getString(R.string.not_synced);
-
- mCache = new CalendarColorCache(context, this);
-
- mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mResolver = context.getContentResolver();
- mActivity = act;
- mFragmentManager = act.getFragmentManager();
- mColorPickerDialog = (CalendarColorPickerDialog)
- mFragmentManager.findFragmentByTag(COLOR_PICKER_DIALOG_TAG);
- mIsTablet = Utils.getConfigBool(context, R.bool.tablet_config);
-
- if (mCalendarsUpdater == null) {
- mCalendarsUpdater = new AsyncCalendarsUpdater(mResolver);
- }
-
- if (acctsCursor == null || acctsCursor.getCount() == 0) {
- Log.i(TAG, "SelectCalendarsAdapter: No accounts were returned!");
- }
- // Collect proper description for account types
- mAuthDescs = AccountManager.get(context).getAuthenticatorTypes();
- for (int i = 0; i < mAuthDescs.length; i++) {
- mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]);
- }
- mView = mActivity.getExpandableListView();
- mRefresh = true;
- mClosedCursorsFlag = false;
-
- mColorViewTouchAreaIncrease = context.getResources()
- .getDimensionPixelSize(R.dimen.color_view_touch_area_increase);
- }
-
- public void startRefreshStopDelay() {
- mRefresh = true;
- mView.postDelayed(mStopRefreshing, REFRESH_DURATION);
- }
-
- public void cancelRefreshStopDelay() {
- mView.removeCallbacks(mStopRefreshing);
- }
-
- /*
- * Write back the changes that have been made. The sync code will pick up any changes and
- * do updates on its own.
- */
- public void doSaveAction() {
- // Cancel the previous operation
- mCalendarsUpdater.cancelOperation(mUpdateToken);
- mUpdateToken++;
- // This is to allow us to do queries and updates with the same AsyncQueryHandler without
- // accidently canceling queries.
- if(mUpdateToken < MIN_UPDATE_TOKEN) {
- mUpdateToken = MIN_UPDATE_TOKEN;
- }
-
- Iterator<Long> changeKeys = mCalendarChanges.keySet().iterator();
- while (changeKeys.hasNext()) {
- long id = changeKeys.next();
- boolean newSynced = mCalendarChanges.get(id);
-
- Uri uri = ContentUris.withAppendedId(Calendars.CONTENT_URI, id);
- ContentValues values = new ContentValues();
- values.put(Calendars.VISIBLE, newSynced ? 1 : 0);
- values.put(Calendars.SYNC_EVENTS, newSynced ? 1 : 0);
- mCalendarsUpdater.startUpdate(mUpdateToken, id, uri, values, null, null);
- }
- }
-
- private static void setText(View view, int id, String text) {
- if (TextUtils.isEmpty(text)) {
- return;
- }
- TextView textView = (TextView) view.findViewById(id);
- textView.setText(text);
- }
-
- /**
- * Gets the label associated with a particular account type. If none found, return null.
- * @param accountType the type of account
- * @return a CharSequence for the label or null if one cannot be found.
- */
- protected CharSequence getLabelForType(final String accountType) {
- CharSequence label = null;
- if (mTypeToAuthDescription.containsKey(accountType)) {
- try {
- AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
- Context authContext = mActivity.createPackageContext(desc.packageName, 0);
- label = authContext.getResources().getText(desc.labelId);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "No label for account type " + ", type " + accountType);
- }
- }
- return label;
- }
-
- @Override
- protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) {
- final long id = cursor.getLong(ID_COLUMN);
- String name = cursor.getString(NAME_COLUMN);
- String owner = cursor.getString(OWNER_COLUMN);
- final String accountName = cursor.getString(ACCOUNT_COLUMN);
- final String accountType = cursor.getString(ACCOUNT_TYPE_COLUMN);
- int color = Utils.getDisplayColorFromColor(cursor.getInt(COLOR_COLUMN));
-
- final View colorSquare = view.findViewById(R.id.color);
- colorSquare.setEnabled(mCache.hasColors(accountName, accountType));
- colorSquare.setBackgroundColor(color);
- final View delegateParent = (View) colorSquare.getParent();
- delegateParent.post(new Runnable() {
-
- @Override
- public void run() {
- final Rect r = new Rect();
- colorSquare.getHitRect(r);
- r.top -= mColorViewTouchAreaIncrease;
- r.bottom += mColorViewTouchAreaIncrease;
- r.left -= mColorViewTouchAreaIncrease;
- r.right += mColorViewTouchAreaIncrease;
- delegateParent.setTouchDelegate(new TouchDelegate(r, colorSquare));
- }
- });
- colorSquare.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- if (!mCache.hasColors(accountName, accountType)) {
- return;
- }
- if (mColorPickerDialog == null) {
- mColorPickerDialog = CalendarColorPickerDialog.newInstance(id, mIsTablet);
- } else {
- mColorPickerDialog.setCalendarId(id);
- }
- mFragmentManager.executePendingTransactions();
- if (!mColorPickerDialog.isAdded()) {
- mColorPickerDialog.show(mFragmentManager, COLOR_PICKER_DIALOG_TAG);
- }
- }
- });
- if (mIsDuplicateName.containsKey(name) && mIsDuplicateName.get(name) &&
- !name.equalsIgnoreCase(owner)) {
- name = new StringBuilder(name)
- .append(Utils.OPEN_EMAIL_MARKER)
- .append(owner)
- .append(Utils.CLOSE_EMAIL_MARKER)
- .toString();
- }
- setText(view, R.id.calendar, name);
-
- // First see if the user has already changed the state of this calendar
- Boolean sync = mCalendarChanges.get(id);
- if (sync == null) {
- sync = cursor.getInt(SYNCED_COLUMN) == 1;
- mCalendarInitialStates.put(id, sync);
- }
-
- CheckBox button = (CheckBox) view.findViewById(R.id.sync);
- button.setChecked(sync);
- setText(view, R.id.status, sync ? mSyncedText : mNotSyncedText);
-
- view.setTag(TAG_ID_CALENDAR_ID, id);
- view.setTag(TAG_ID_SYNC_CHECKBOX, button);
- view.setOnClickListener(this);
- }
-
- @Override
- protected void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) {
- int accountColumn = cursor.getColumnIndexOrThrow(Calendars.ACCOUNT_NAME);
- int accountTypeColumn = cursor.getColumnIndexOrThrow(Calendars.ACCOUNT_TYPE);
- String account = cursor.getString(accountColumn);
- String accountType = cursor.getString(accountTypeColumn);
- CharSequence accountLabel = getLabelForType(accountType);
- setText(view, R.id.account, account);
- if (accountLabel != null) {
- setText(view, R.id.account_type, accountLabel.toString());
- }
- }
-
- @Override
- protected Cursor getChildrenCursor(Cursor groupCursor) {
- int accountColumn = groupCursor.getColumnIndexOrThrow(Calendars.ACCOUNT_NAME);
- int accountTypeColumn = groupCursor.getColumnIndexOrThrow(Calendars.ACCOUNT_TYPE);
- String account = groupCursor.getString(accountColumn);
- String accountType = groupCursor.getString(accountTypeColumn);
- //Get all the calendars for just this account.
- Cursor childCursor = mChildrenCursors.get(accountType + "#" + account);
- new RefreshCalendars(groupCursor.getPosition(), account, accountType).run();
- return childCursor;
- }
-
- @Override
- protected View newChildView(Context context, Cursor cursor, boolean isLastChild,
- ViewGroup parent) {
- return mInflater.inflate(R.layout.calendar_sync_item, parent, false);
- }
-
- @Override
- protected View newGroupView(Context context, Cursor cursor, boolean isExpanded,
- ViewGroup parent) {
- return mInflater.inflate(R.layout.account_item, parent, false);
- }
-
- public void closeChildrenCursors() {
- synchronized (mChildrenCursors) {
- for (String key : mChildrenCursors.keySet()) {
- Cursor cursor = mChildrenCursors.get(key);
- if (!cursor.isClosed()) {
- cursor.close();
- }
- }
- mChildrenCursors.clear();
- mClosedCursorsFlag = true;
- }
- }
-
- private class RefreshCalendars implements Runnable {
-
- int mToken;
- String mAccount;
- String mAccountType;
-
- public RefreshCalendars(int token, String account, String accountType) {
- mToken = token;
- mAccount = account;
- mAccountType = accountType;
- }
-
- @Override
- public void run() {
- mCalendarsUpdater.cancelOperation(mToken);
- // Set up a refresh for some point in the future if we haven't stopped updates yet
- if(mRefresh) {
- mView.postDelayed(new RefreshCalendars(mToken, mAccount, mAccountType),
- REFRESH_DELAY);
- }
- mCalendarsUpdater.startQuery(mToken,
- mAccountType + "#" + mAccount,
- Calendars.CONTENT_URI, PROJECTION,
- ACCOUNT_SELECTION,
- new String[] { mAccount, mAccountType } /*selectionArgs*/,
- CALENDARS_ORDERBY);
- }
- }
-
- @Override
- public void onCalendarColorsLoaded() {
- notifyDataSetChanged();
- }
-}
diff --git a/src/com/android/calendar/selectcalendars/SelectVisibleCalendarsActivity.java b/src/com/android/calendar/selectcalendars/SelectVisibleCalendarsActivity.java
deleted file mode 100644
index b8a9ba3f..00000000
--- a/src/com/android/calendar/selectcalendars/SelectVisibleCalendarsActivity.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2011 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.selectcalendars;
-
-import android.app.ActionBar;
-import android.app.FragmentTransaction;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.os.Bundle;
-import android.os.Handler;
-import android.provider.CalendarContract;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-
-import com.android.calendar.AbstractCalendarActivity;
-import com.android.calendar.CalendarController;
-import com.android.calendar.CalendarController.EventType;
-import com.android.calendar.CalendarController.ViewType;
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-
-public class SelectVisibleCalendarsActivity extends AbstractCalendarActivity {
- private SelectVisibleCalendarsFragment mFragment;
- private CalendarController mController;
-
- // Create an observer so that we can update the views whenever a
- // Calendar event changes.
- private final ContentObserver mObserver = new ContentObserver(new Handler()) {
- @Override
- public boolean deliverSelfNotifications() {
- return true;
- }
-
- @Override
- public void onChange(boolean selfChange) {
- mController.sendEvent(this, EventType.EVENTS_CHANGED, null, null, -1, ViewType.CURRENT);
- }
- };
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- setContentView(R.layout.simple_frame_layout);
-
- mController = CalendarController.getInstance(this);
- mFragment = (SelectVisibleCalendarsFragment) getFragmentManager().findFragmentById(
- R.id.main_frame);
-
- if (mFragment == null) {
- mFragment = new SelectVisibleCalendarsFragment(R.layout.calendar_sync_item);
-
- FragmentTransaction ft = getFragmentManager().beginTransaction();
- ft.replace(R.id.main_frame, mFragment);
- ft.show(mFragment);
- ft.commit();
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- getContentResolver().registerContentObserver(CalendarContract.Events.CONTENT_URI,
- true, mObserver);
- }
-
- @Override
- public void onPause() {
- super.onPause();
- getContentResolver().unregisterContentObserver(mObserver);
- }
-
- // Needs to be in proguard whitelist
- // Specified as listener via android:onClick in a layout xml
- public void handleSelectSyncedCalendarsClicked(View v) {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setClass(this, SelectSyncedCalendarsMultiAccountActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
- startActivity(intent);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getActionBar()
- .setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- Utils.returnToCalendarHome(this);
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-}
diff --git a/src/com/android/calendar/selectcalendars/SelectVisibleCalendarsFragment.java b/src/com/android/calendar/selectcalendars/SelectVisibleCalendarsFragment.java
deleted file mode 100644
index 53028968..00000000
--- a/src/com/android/calendar/selectcalendars/SelectVisibleCalendarsFragment.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.calendar.selectcalendars;
-
-import android.app.Activity;
-import android.app.Fragment;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.CalendarContract.Calendars;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ListView;
-
-import com.android.calendar.AsyncQueryService;
-import com.android.calendar.CalendarController;
-import com.android.calendar.CalendarController.EventInfo;
-import com.android.calendar.CalendarController.EventType;
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-import com.android.calendar.selectcalendars.CalendarColorCache.OnCalendarColorsLoadedListener;
-
-public class SelectVisibleCalendarsFragment extends Fragment
- implements AdapterView.OnItemClickListener, CalendarController.EventHandler,
- OnCalendarColorsLoadedListener {
-
- private static final String TAG = "Calendar";
- private static final String IS_PRIMARY = "\"primary\"";
- private static final String SELECTION = Calendars.SYNC_EVENTS + "=?";
- private static final String[] SELECTION_ARGS = new String[] {"1"};
-
- private static final String[] PROJECTION = new String[] {
- Calendars._ID,
- Calendars.ACCOUNT_NAME,
- Calendars.ACCOUNT_TYPE,
- Calendars.OWNER_ACCOUNT,
- Calendars.CALENDAR_DISPLAY_NAME,
- Calendars.CALENDAR_COLOR,
- Calendars.VISIBLE,
- Calendars.SYNC_EVENTS,
- "(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + IS_PRIMARY,
- };
- private static int mUpdateToken;
- private static int mQueryToken;
- private static int mCalendarItemLayout = R.layout.mini_calendar_item;
-
- private View mView = null;
- private CalendarController mController;
- private ListView mList;
- private SelectCalendarsSimpleAdapter mAdapter;
- private Activity mContext;
- private AsyncQueryService mService;
- private Cursor mCursor;
-
- public SelectVisibleCalendarsFragment() {
- }
-
- public SelectVisibleCalendarsFragment(int itemLayout) {
- mCalendarItemLayout = itemLayout;
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- mContext = activity;
- mController = CalendarController.getInstance(activity);
- mController.registerEventHandler(R.layout.select_calendars_fragment, this);
- mService = new AsyncQueryService(activity) {
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- mAdapter.changeCursor(cursor);
- mCursor = cursor;
- }
- };
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- mController.deregisterEventHandler(R.layout.select_calendars_fragment);
- if (mCursor != null) {
- mAdapter.changeCursor(null);
- mCursor.close();
- mCursor = null;
- }
- }
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- super.onCreateView(inflater, container, savedInstanceState);
- mView = inflater.inflate(R.layout.select_calendars_fragment, null);
- mList = (ListView)mView.findViewById(R.id.list);
-
- // Hide the Calendars to Sync button on tablets for now.
- // Long terms stick it in the list of calendars
- if (Utils.getConfigBool(getActivity(), R.bool.multiple_pane_config)) {
- // Don't show dividers on tablets
- mList.setDivider(null);
- View v = mView.findViewById(R.id.manage_sync_set);
- if (v != null) {
- v.setVisibility(View.GONE);
- }
- }
- return mView;
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- mAdapter = new SelectCalendarsSimpleAdapter(mContext, mCalendarItemLayout, null,
- getFragmentManager());
- mList.setAdapter(mAdapter);
- mList.setOnItemClickListener(this);
- }
-
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- if (mAdapter == null || mAdapter.getCount() <= position) {
- return;
- }
- toggleVisibility(position);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- mQueryToken = mService.getNextToken();
- mService.startQuery(mQueryToken, null, Calendars.CONTENT_URI, PROJECTION, SELECTION,
- SELECTION_ARGS, Calendars.ACCOUNT_NAME);
- }
-
- /*
- * Write back the changes that have been made.
- */
- public void toggleVisibility(int position) {
- mUpdateToken = mService.getNextToken();
- Uri uri = ContentUris.withAppendedId(Calendars.CONTENT_URI, mAdapter.getItemId(position));
- ContentValues values = new ContentValues();
- // Toggle the current setting
- int visibility = mAdapter.getVisible(position)^1;
- values.put(Calendars.VISIBLE, visibility);
- mService.startUpdate(mUpdateToken, null, uri, values, null, null, 0);
- mAdapter.setVisible(position, visibility);
- }
-
- @Override
- public void eventsChanged() {
- if (mService != null) {
- mService.cancelOperation(mQueryToken);
- mQueryToken = mService.getNextToken();
- mService.startQuery(mQueryToken, null, Calendars.CONTENT_URI, PROJECTION, SELECTION,
- SELECTION_ARGS, Calendars.ACCOUNT_NAME);
- }
- }
-
- @Override
- public long getSupportedEventTypes() {
- return EventType.EVENTS_CHANGED;
- }
-
- @Override
- public void handleEvent(EventInfo event) {
- eventsChanged();
- }
-
- @Override
- public void onCalendarColorsLoaded() {
- if (mAdapter != null) {
- mAdapter.notifyDataSetChanged();
- }
- }
-}
diff --git a/src/com/android/calendar/widget/CalendarAppWidgetProvider.java b/src/com/android/calendar/widget/CalendarAppWidgetProvider.java
index 7da2ba17..2864d47a 100644
--- a/src/com/android/calendar/widget/CalendarAppWidgetProvider.java
+++ b/src/com/android/calendar/widget/CalendarAppWidgetProvider.java
@@ -227,14 +227,4 @@ public class CalendarAppWidgetProvider extends AppWidgetProvider {
return fillInIntent;
}
-
-// private static PendingIntent getNewEventPendingIntent(Context context) {
-// Intent newEventIntent = new Intent(Intent.ACTION_EDIT);
-// newEventIntent.setClass(context, EditEventActivity.class);
-// Builder builder = CalendarContract.CONTENT_URI.buildUpon();
-// builder.appendPath("events");
-// newEventIntent.setData(builder.build());
-// return PendingIntent.getActivity(context, 0, newEventIntent,
-// PendingIntent.FLAG_UPDATE_CURRENT);
-// }
}
diff --git a/src/com/android/calendar/widget/CalendarAppWidgetService.java b/src/com/android/calendar/widget/CalendarAppWidgetService.java
index b51b004b..6329463b 100644
--- a/src/com/android/calendar/widget/CalendarAppWidgetService.java
+++ b/src/com/android/calendar/widget/CalendarAppWidgetService.java
@@ -286,8 +286,6 @@ public class CalendarAppWidgetService extends RemoteViewsService {
views.setInt(R.id.title, "setTextColor", mDeclinedColor);
views.setInt(R.id.when, "setTextColor", mDeclinedColor);
views.setInt(R.id.where, "setTextColor", mDeclinedColor);
- // views.setInt(R.id.agenda_item_color, "setDrawStyle",
- // ColorChipView.DRAW_CROSS_HATCHED);
views.setInt(R.id.agenda_item_color, "setImageResource",
R.drawable.widget_chip_responded_bg);
// 40% opacity
diff --git a/tests/src/com/android/calendar/AsyncQueryServiceTest.java b/tests/src/com/android/calendar/AsyncQueryServiceTest.java
deleted file mode 100644
index 70dbde34..00000000
--- a/tests/src/com/android/calendar/AsyncQueryServiceTest.java
+++ /dev/null
@@ -1,661 +0,0 @@
-/*
- * 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 com.android.calendar.AsyncQueryService.Operation;
-import com.android.calendar.AsyncQueryServiceHelper.OperationInfo;
-
-import android.content.ComponentName;
-import android.content.ContentProvider;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Message;
-import android.test.IsolatedContext;
-import android.test.RenamingDelegatingContext;
-import android.test.ServiceTestCase;
-import android.test.mock.MockContentResolver;
-import android.test.mock.MockContext;
-import android.test.mock.MockCursor;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Smoke;
-import android.util.Log;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Unit tests for {@link android.text.format.DateUtils#formatDateRange}.
- */
-public class AsyncQueryServiceTest extends ServiceTestCase<AsyncQueryServiceHelper> {
- private static final String TAG = "AsyncQueryServiceTest";
-
- private static final String AUTHORITY_URI = "content://AsyncQueryAuthority/";
-
- private static final String AUTHORITY = "AsyncQueryAuthority";
-
- private static final int MIN_DELAY = 50;
-
- private static final int BASE_TEST_WAIT_TIME = MIN_DELAY * 5;
-
- private static int mId = 0;
-
- private static final String[] TEST_PROJECTION = new String[] {
- "col1", "col2", "col3"
- };
-
- private static final String TEST_SELECTION = "selection";
-
- private static final String[] TEST_SELECTION_ARGS = new String[] {
- "arg1", "arg2", "arg3"
- };
-
- public AsyncQueryServiceTest() {
- super(AsyncQueryServiceHelper.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- }
-
- private class MockContext2 extends MockContext {
- @Override
- public Resources getResources() {
- return getContext().getResources();
- }
-
- @Override
- public File getDir(String name, int mode) {
- return getContext().getDir("mockcontext2_+" + name, mode);
- }
-
- @Override
- public Context getApplicationContext() {
- return this;
- }
- }
-
- @Smoke
- @SmallTest
- public void testQuery() throws Exception {
- int index = 0;
- final OperationInfo[] work = new OperationInfo[1];
- work[index] = new OperationInfo();
- work[index].op = Operation.EVENT_ARG_QUERY;
-
- work[index].token = ++mId;
- work[index].cookie = ++mId;
- work[index].uri = Uri.parse(AUTHORITY_URI + "blah");
- work[index].projection = TEST_PROJECTION;
- work[index].selection = TEST_SELECTION;
- work[index].selectionArgs = TEST_SELECTION_ARGS;
- work[index].orderBy = "order";
-
- work[index].delayMillis = 0;
- work[index].result = new TestCursor();
-
- TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(work), work);
- aqs.startQuery(work[index].token, work[index].cookie, work[index].uri,
- work[index].projection, work[index].selection, work[index].selectionArgs,
- work[index].orderBy);
-
- Log.d(TAG, "testQuery Waiting >>>>>>>>>>>");
- assertEquals("Not all operations were executed.", work.length, aqs
- .waitForCompletion(BASE_TEST_WAIT_TIME));
- Log.d(TAG, "testQuery Done <<<<<<<<<<<<<<");
- }
-
- @SmallTest
- public void testInsert() throws Exception {
- int index = 0;
- final OperationInfo[] work = new OperationInfo[1];
- work[index] = new OperationInfo();
- work[index].op = Operation.EVENT_ARG_INSERT;
-
- work[index].token = ++mId;
- work[index].cookie = ++mId;
- work[index].uri = Uri.parse(AUTHORITY_URI + "blah");
- work[index].values = new ContentValues();
- work[index].values.put("key", ++mId);
-
- work[index].delayMillis = 0;
- work[index].result = Uri.parse(AUTHORITY_URI + "Result=" + ++mId);
-
- TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(work), work);
- aqs.startInsert(work[index].token, work[index].cookie, work[index].uri, work[index].values,
- work[index].delayMillis);
-
- Log.d(TAG, "testInsert Waiting >>>>>>>>>>>");
- assertEquals("Not all operations were executed.", work.length, aqs
- .waitForCompletion(BASE_TEST_WAIT_TIME));
- Log.d(TAG, "testInsert Done <<<<<<<<<<<<<<");
- }
-
- @SmallTest
- public void testUpdate() throws Exception {
- int index = 0;
- final OperationInfo[] work = new OperationInfo[1];
- work[index] = new OperationInfo();
- work[index].op = Operation.EVENT_ARG_UPDATE;
-
- work[index].token = ++mId;
- work[index].cookie = ++mId;
- work[index].uri = Uri.parse(AUTHORITY_URI + ++mId);
- work[index].values = new ContentValues();
- work[index].values.put("key", ++mId);
- work[index].selection = TEST_SELECTION;
- work[index].selectionArgs = TEST_SELECTION_ARGS;
-
- work[index].delayMillis = 0;
- work[index].result = ++mId;
-
- TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(work), work);
- aqs.startUpdate(work[index].token, work[index].cookie, work[index].uri, work[index].values,
- work[index].selection, work[index].selectionArgs, work[index].delayMillis);
-
- Log.d(TAG, "testUpdate Waiting >>>>>>>>>>>");
- assertEquals("Not all operations were executed.", work.length, aqs
- .waitForCompletion(BASE_TEST_WAIT_TIME));
- Log.d(TAG, "testUpdate Done <<<<<<<<<<<<<<");
- }
-
- @SmallTest
- public void testDelete() throws Exception {
- int index = 0;
- final OperationInfo[] work = new OperationInfo[1];
- work[index] = new OperationInfo();
- work[index].op = Operation.EVENT_ARG_DELETE;
-
- work[index].token = ++mId;
- work[index].cookie = ++mId;
- work[index].uri = Uri.parse(AUTHORITY_URI + "blah");
- work[index].selection = TEST_SELECTION;
- work[index].selectionArgs = TEST_SELECTION_ARGS;
-
- work[index].delayMillis = 0;
- work[index].result = ++mId;
-
- TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(work), work);
- aqs.startDelete(work[index].token,
- work[index].cookie,
- work[index].uri,
- work[index].selection,
- work[index].selectionArgs,
- work[index].delayMillis);
-
- Log.d(TAG, "testDelete Waiting >>>>>>>>>>>");
- assertEquals("Not all operations were executed.", work.length, aqs
- .waitForCompletion(BASE_TEST_WAIT_TIME));
- Log.d(TAG, "testDelete Done <<<<<<<<<<<<<<");
- }
-
- @SmallTest
- public void testBatch() throws Exception {
- int index = 0;
- final OperationInfo[] work = new OperationInfo[1];
- work[index] = new OperationInfo();
- work[index].op = Operation.EVENT_ARG_BATCH;
-
- work[index].token = ++mId;
- work[index].cookie = ++mId;
- work[index].authority = AUTHORITY;
- work[index].cpo = new ArrayList<ContentProviderOperation>();
- work[index].cpo.add(ContentProviderOperation.newInsert(Uri.parse(AUTHORITY_URI + ++mId))
- .build());
-
- work[index].delayMillis = 0;
- ContentProviderResult[] resultArray = new ContentProviderResult[1];
- resultArray[0] = new ContentProviderResult(++mId);
- work[index].result = resultArray;
-
- TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(work), work);
- aqs.startBatch(work[index].token,
- work[index].cookie,
- work[index].authority,
- work[index].cpo,
- work[index].delayMillis);
-
- Log.d(TAG, "testBatch Waiting >>>>>>>>>>>");
- assertEquals("Not all operations were executed.", work.length, aqs
- .waitForCompletion(BASE_TEST_WAIT_TIME));
- Log.d(TAG, "testBatch Done <<<<<<<<<<<<<<");
- }
-
- @LargeTest
- public void testDelay() throws Exception {
- // Tests the ordering of the workqueue
- int index = 0;
- OperationInfo[] work = new OperationInfo[5];
- work[index++] = generateWork(MIN_DELAY * 2);
- work[index++] = generateWork(0);
- work[index++] = generateWork(MIN_DELAY * 1);
- work[index++] = generateWork(0);
- work[index++] = generateWork(MIN_DELAY * 3);
-
- OperationInfo[] sorted = generateSortedWork(work, work.length);
-
- TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(sorted), sorted);
- startWork(aqs, work);
-
- Log.d(TAG, "testDelay Waiting >>>>>>>>>>>");
- assertEquals("Not all operations were executed.", work.length, aqs
- .waitForCompletion(BASE_TEST_WAIT_TIME));
- Log.d(TAG, "testDelay Done <<<<<<<<<<<<<<");
- }
-
- @LargeTest
- public void testCancel_simpleCancelLastTest() throws Exception {
- int index = 0;
- OperationInfo[] work = new OperationInfo[5];
- work[index++] = generateWork(MIN_DELAY * 2);
- work[index++] = generateWork(0);
- work[index++] = generateWork(MIN_DELAY);
- work[index++] = generateWork(0);
- work[index] = generateWork(MIN_DELAY * 3);
-
- // Not part of the expected as it will be canceled
- OperationInfo toBeCancelled1 = work[index];
- OperationInfo[] expected = generateSortedWork(work, work.length - 1);
-
- TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(expected), expected);
- startWork(aqs, work);
- Operation lastOne = aqs.getLastCancelableOperation();
- // Log.d(TAG, "lastOne = " + lastOne.toString());
- // Log.d(TAG, "toBeCancelled1 = " + toBeCancelled1.toString());
- assertTrue("1) delay=3 is not last", toBeCancelled1.equivalent(lastOne));
- assertEquals("Can't cancel delay 3", 1, aqs.cancelOperation(lastOne.token));
-
- Log.d(TAG, "testCancel_simpleCancelLastTest Waiting >>>>>>>>>>>");
- assertEquals("Not all operations were executed.", expected.length, aqs
- .waitForCompletion(BASE_TEST_WAIT_TIME));
- Log.d(TAG, "testCancel_simpleCancelLastTest Done <<<<<<<<<<<<<<");
- }
-
- @LargeTest
- public void testCancel_cancelSecondToLast() throws Exception {
- int index = 0;
- OperationInfo[] work = new OperationInfo[5];
- work[index++] = generateWork(MIN_DELAY * 2);
- work[index++] = generateWork(0);
- work[index++] = generateWork(MIN_DELAY);
- work[index++] = generateWork(0);
- work[index] = generateWork(MIN_DELAY * 3);
-
- // Not part of the expected as it will be canceled
- OperationInfo toBeCancelled1 = work[index];
- OperationInfo[] expected = new OperationInfo[4];
- expected[0] = work[1]; // delay = 0
- expected[1] = work[3]; // delay = 0
- expected[2] = work[2]; // delay = MIN_DELAY
- expected[3] = work[4]; // delay = MIN_DELAY * 3
-
- TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(expected), expected);
- startWork(aqs, work);
-
- Operation lastOne = aqs.getLastCancelableOperation(); // delay = 3
- assertTrue("2) delay=3 is not last", toBeCancelled1.equivalent(lastOne));
- assertEquals("Can't cancel delay 2", 1, aqs.cancelOperation(work[0].token));
- assertEquals("Delay 2 should be gone", 0, aqs.cancelOperation(work[0].token));
-
- Log.d(TAG, "testCancel_cancelSecondToLast Waiting >>>>>>>>>>>");
- assertEquals("Not all operations were executed.", expected.length, aqs
- .waitForCompletion(BASE_TEST_WAIT_TIME));
- Log.d(TAG, "testCancel_cancelSecondToLast Done <<<<<<<<<<<<<<");
- }
-
- @LargeTest
- public void testCancel_multipleCancels() throws Exception {
- int index = 0;
- OperationInfo[] work = new OperationInfo[5];
- work[index++] = generateWork(MIN_DELAY * 2);
- work[index++] = generateWork(0);
- work[index++] = generateWork(MIN_DELAY);
- work[index++] = generateWork(0);
- work[index] = generateWork(MIN_DELAY * 3);
-
- // Not part of the expected as it will be canceled
- OperationInfo[] expected = new OperationInfo[3];
- expected[0] = work[1]; // delay = 0
- expected[1] = work[3]; // delay = 0
- expected[2] = work[2]; // delay = MIN_DELAY
-
- TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(expected), expected);
- startWork(aqs, work);
-
- Operation lastOne = aqs.getLastCancelableOperation(); // delay = 3
- assertTrue("3) delay=3 is not last", work[4].equivalent(lastOne));
- assertEquals("Can't cancel delay 2", 1, aqs.cancelOperation(work[0].token));
- assertEquals("Delay 2 should be gone", 0, aqs.cancelOperation(work[0].token));
- assertEquals("Can't cancel delay 3", 1, aqs.cancelOperation(work[4].token));
- assertEquals("Delay 3 should be gone", 0, aqs.cancelOperation(work[4].token));
-
- Log.d(TAG, "testCancel_multipleCancels Waiting >>>>>>>>>>>");
- assertEquals("Not all operations were executed.", expected.length, aqs
- .waitForCompletion(BASE_TEST_WAIT_TIME));
- Log.d(TAG, "testCancel_multipleCancels Done <<<<<<<<<<<<<<");
- }
-
- private OperationInfo generateWork(long delayMillis) {
- OperationInfo work = new OperationInfo();
- work.op = Operation.EVENT_ARG_DELETE;
-
- work.token = ++mId;
- work.cookie = 100 + work.token;
- work.uri = Uri.parse(AUTHORITY_URI + "blah");
- work.selection = TEST_SELECTION;
- work.selectionArgs = TEST_SELECTION_ARGS;
-
- work.delayMillis = delayMillis;
- work.result = 1000 + work.token;
- return work;
- }
-
- private void startWork(TestAsyncQueryService aqs, OperationInfo[] work) {
- for (OperationInfo w : work) {
- if (w != null) {
- aqs.startDelete(w.token, w.cookie, w.uri, w.selection, w.selectionArgs,
- w.delayMillis);
- }
- }
- }
-
- OperationInfo[] generateSortedWork(OperationInfo[] work, int length) {
- OperationInfo[] sorted = new OperationInfo[length];
- System.arraycopy(work, 0, sorted, 0, length);
-
- // Set the scheduled time so they get sorted properly
- for (OperationInfo w : sorted) {
- if (w != null) {
- w.calculateScheduledTime();
- }
- }
-
- // Stable sort by scheduled time
- Arrays.sort(sorted);
-
- Log.d(TAG, "Unsorted work: " + work.length);
- for (OperationInfo w : work) {
- if (w != null) {
- Log.d(TAG, "Token#" + w.token + " delay=" + w.delayMillis);
- }
- }
- Log.d(TAG, "Sorted work: " + sorted.length);
- for (OperationInfo w : sorted) {
- if (w != null) {
- Log.d(TAG, "Token#" + w.token + " delay=" + w.delayMillis);
- }
- }
-
- return sorted;
- }
-
- private Context buildTestContext(final OperationInfo[] work) {
- MockContext context = new MockContext() {
- MockContentResolver mResolver;
-
- @Override
- public ContentResolver getContentResolver() {
- if (mResolver == null) {
- mResolver = new MockContentResolver();
-
- final String filenamePrefix = "test.";
- RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(
- new MockContext2(), getContext(), filenamePrefix);
- IsolatedContext providerContext =
- new IsolatedContext(mResolver, targetContextWrapper);
-
- ContentProvider provider = new TestProvider(work);
- provider.attachInfo(providerContext, null);
-
- mResolver.addProvider(AUTHORITY, provider);
- }
- return mResolver;
- }
-
- @Override
- public String getPackageName() {
- return AsyncQueryServiceTest.class.getPackage().getName();
- }
-
- @Override
- public ComponentName startService(Intent service) {
- AsyncQueryServiceTest.this.startService(service);
- return service.getComponent();
- }
- };
-
- return context;
- }
-
- private final class TestCursor extends MockCursor {
- int mUnique = ++mId;
-
- @Override
- public int getCount() {
- return mUnique;
- }
- }
-
- /**
- * TestAsyncQueryService takes the expected results in the constructor. They
- * are used to verify the data passed to the callbacks.
- */
- class TestAsyncQueryService extends AsyncQueryService {
- int mIndex = 0;
-
- private OperationInfo[] mWork;
-
- private Semaphore mCountingSemaphore;
-
- public TestAsyncQueryService(Context context, OperationInfo[] work) {
- super(context);
- mCountingSemaphore = new Semaphore(0);
-
- // run in a separate thread but call the same code
- HandlerThread thread = new HandlerThread("TestAsyncQueryService");
- thread.start();
- super.setTestHandler(new Handler(thread.getLooper()) {
- @Override
- public void handleMessage(Message msg) {
- TestAsyncQueryService.this.handleMessage(msg);
- }
- });
-
- mWork = work;
- }
-
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- Log.d(TAG, "onQueryComplete tid=" + Thread.currentThread().getId());
- Log.d(TAG, "mWork.length=" + mWork.length + " mIndex=" + mIndex);
-
- assertEquals(mWork[mIndex].op, Operation.EVENT_ARG_QUERY);
- assertEquals(mWork[mIndex].token, token);
- /*
- * Even though our TestProvider returned mWork[mIndex].result, it is
- * wrapped with new'ed CursorWrapperInner and there's no equal() in
- * CursorWrapperInner. assertEquals the two cursor will always fail.
- * So just compare the count which will be unique in our TestCursor;
- */
- assertEquals(((Cursor) mWork[mIndex].result).getCount(), cursor.getCount());
-
- mIndex++;
- mCountingSemaphore.release();
- }
-
- @Override
- protected void onInsertComplete(int token, Object cookie, Uri uri) {
- Log.d(TAG, "onInsertComplete tid=" + Thread.currentThread().getId());
- Log.d(TAG, "mWork.length=" + mWork.length + " mIndex=" + mIndex);
-
- assertEquals(mWork[mIndex].op, Operation.EVENT_ARG_INSERT);
- assertEquals(mWork[mIndex].token, token);
- assertEquals(mWork[mIndex].result, uri);
-
- mIndex++;
- mCountingSemaphore.release();
- }
-
- @Override
- protected void onUpdateComplete(int token, Object cookie, int result) {
- Log.d(TAG, "onUpdateComplete tid=" + Thread.currentThread().getId());
- Log.d(TAG, "mWork.length=" + mWork.length + " mIndex=" + mIndex);
-
- assertEquals(mWork[mIndex].op, Operation.EVENT_ARG_UPDATE);
- assertEquals(mWork[mIndex].token, token);
- assertEquals(mWork[mIndex].result, result);
-
- mIndex++;
- mCountingSemaphore.release();
- }
-
- @Override
- protected void onDeleteComplete(int token, Object cookie, int result) {
- Log.d(TAG, "onDeleteComplete tid=" + Thread.currentThread().getId());
- Log.d(TAG, "mWork.length=" + mWork.length + " mIndex=" + mIndex);
-
- assertEquals(mWork[mIndex].op, Operation.EVENT_ARG_DELETE);
- assertEquals(mWork[mIndex].token, token);
- assertEquals(mWork[mIndex].result, result);
-
- mIndex++;
- mCountingSemaphore.release();
- }
-
- @Override
- protected void onBatchComplete(int token, Object cookie, ContentProviderResult[] results) {
- Log.d(TAG, "onBatchComplete tid=" + Thread.currentThread().getId());
- Log.d(TAG, "mWork.length=" + mWork.length + " mIndex=" + mIndex);
-
- assertEquals(mWork[mIndex].op, Operation.EVENT_ARG_BATCH);
- assertEquals(mWork[mIndex].token, token);
-
- ContentProviderResult[] expected = (ContentProviderResult[]) mWork[mIndex].result;
- assertEquals(expected.length, results.length);
- for (int i = 0; i < expected.length; ++i) {
- assertEquals(expected[i].count, results[i].count);
- assertEquals(expected[i].uri, results[i].uri);
- }
-
- mIndex++;
- mCountingSemaphore.release();
- }
-
- public int waitForCompletion(long timeoutMills) {
- Log.d(TAG, "waitForCompletion tid=" + Thread.currentThread().getId());
- int count = 0;
- try {
- while (count < mWork.length) {
- if (!mCountingSemaphore.tryAcquire(timeoutMills, TimeUnit.MILLISECONDS)) {
- break;
- }
- count++;
- }
- } catch (InterruptedException e) {
- }
- return count;
- }
- }
-
- /**
- * This gets called by AsyncQueryServiceHelper to read or write the data. It
- * also verifies the data against the data passed in the constructor
- */
- class TestProvider extends ContentProvider {
- OperationInfo[] mWork;
-
- int index = 0;
-
- public TestProvider(OperationInfo[] work) {
- mWork = work;
- }
-
- @Override
- public final Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String orderBy) {
- Log.d(TAG, "Provider query index=" + index);
- assertEquals(mWork[index].op, Operation.EVENT_ARG_QUERY);
- assertEquals(mWork[index].uri, uri);
- assertEquals(mWork[index].projection, projection);
- assertEquals(mWork[index].selection, selection);
- assertEquals(mWork[index].selectionArgs, selectionArgs);
- assertEquals(mWork[index].orderBy, orderBy);
- return (Cursor) mWork[index++].result;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- Log.d(TAG, "Provider insert index=" + index);
- assertEquals(mWork[index].op, Operation.EVENT_ARG_INSERT);
- assertEquals(mWork[index].uri, uri);
- assertEquals(mWork[index].values, values);
- return (Uri) mWork[index++].result;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- Log.d(TAG, "Provider update index=" + index);
- assertEquals(mWork[index].op, Operation.EVENT_ARG_UPDATE);
- assertEquals(mWork[index].uri, uri);
- assertEquals(mWork[index].values, values);
- assertEquals(mWork[index].selection, selection);
- assertEquals(mWork[index].selectionArgs, selectionArgs);
- return (Integer) mWork[index++].result;
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- Log.d(TAG, "Provider delete index=" + index);
- assertEquals(mWork[index].op, Operation.EVENT_ARG_DELETE);
- assertEquals(mWork[index].uri, uri);
- assertEquals(mWork[index].selection, selection);
- assertEquals(mWork[index].selectionArgs, selectionArgs);
- return (Integer) mWork[index++].result;
- }
-
- @Override
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) {
- Log.d(TAG, "Provider applyBatch index=" + index);
- assertEquals(mWork[index].op, Operation.EVENT_ARG_BATCH);
- assertEquals(mWork[index].cpo, operations);
- return (ContentProviderResult[]) mWork[index++].result;
- }
-
- @Override
- public String getType(Uri uri) {
- return null;
- }
-
- @Override
- public boolean onCreate() {
- return false;
- }
- }
-}
diff --git a/tests/src/com/android/calendar/DbTestUtils.java b/tests/src/com/android/calendar/DbTestUtils.java
index ed9b5e91..508dc2ef 100644
--- a/tests/src/com/android/calendar/DbTestUtils.java
+++ b/tests/src/com/android/calendar/DbTestUtils.java
@@ -66,6 +66,10 @@ class DbTestUtils {
return resources;
}
+ public int getUserId() {
+ return 0;
+ }
+
public void setSharedPreferences(SharedPreferences sharedPreferences) {
this.sharedPreferences = sharedPreferences;
}
diff --git a/tests/src/com/android/calendar/FormatDateRangeTest.java b/tests/src/com/android/calendar/FormatDateRangeTest.java
index 1ba3ecc8..7736bdc3 100644
--- a/tests/src/com/android/calendar/FormatDateRangeTest.java
+++ b/tests/src/com/android/calendar/FormatDateRangeTest.java
@@ -73,29 +73,29 @@ public class FormatDateRangeTest extends AndroidTestCase {
DateTest[] tests = {
new DateTest(0, 10, 9, 8, 0, 0, 10, 9, 11, 0,
- DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "8am \u2013 11am"),
+ DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "8 \u2013 11 AM"),
new DateTest(0, 10, 9, 8, 0, 0, 10, 9, 11, 0,
- DateUtils.FORMAT_SHOW_TIME, "8:00AM \u2013 11:00AM"),
+ DateUtils.FORMAT_SHOW_TIME, "8:00 \u2013 11:00 AM"),
new DateTest(0, 10, 9, 8, 0, 0, 10, 9, 17, 0,
DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR, "08:00 \u2013 17:00"),
new DateTest(0, 10, 9, 8, 0, 0, 10, 9, 12, 0,
- DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "8am \u2013 noon"),
+ DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "8 AM \u2013 12 PM"),
new DateTest(0, 10, 9, 8, 0, 0, 10, 9, 12, 0,
DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_NO_NOON | DateUtils.FORMAT_ABBREV_ALL,
- "8am \u2013 12pm"),
+ "8 AM \u2013 12 PM"),
new DateTest(0, 10, 9, 8, 0, 0, 10, 9, 12, 0,
DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_CAP_NOON | DateUtils.FORMAT_ABBREV_ALL,
- "8am \u2013 Noon"),
+ "8 AM \u2013 12 PM"),
new DateTest(0, 10, 9, 10, 30, 0, 10, 9, 13, 0,
- DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "10:30AM \u2013 1pm"),
+ DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "10:30 AM \u2013 1:00 PM"),
new DateTest(0, 10, 9, 13, 0, 0, 10, 9, 14, 0,
- DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "1pm \u2013 2pm"),
+ DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "1 \u2013 2 PM"),
new DateTest(0, 10, 9, 0, 0, 0, 10, 9, 14, 0,
- DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "12am \u2013 2pm"),
+ DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "12 AM \u2013 2 PM"),
new DateTest(0, 10, 9, 20, 0, 0, 10, 10, 0, 0,
- DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "8pm \u2013 midnight"),
+ DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "8 PM \u2013 12 AM"),
new DateTest(0, 10, 10, 0, 0,
- DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "12am"),
+ DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "12 AM"),
new DateTest(0, 10, 9, 20, 0, 0, 10, 10, 0, 0,
DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR | DateUtils.FORMAT_ABBREV_ALL,
"20:00 \u2013 00:00"),
@@ -114,15 +114,15 @@ public class FormatDateRangeTest extends AndroidTestCase {
"Nov 10"),
new DateTest(0, 10, 9, 20, 0, 0, 10, 10, 0, 0,
DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_NO_MIDNIGHT | DateUtils.FORMAT_ABBREV_ALL,
- "8pm \u2013 12am"),
+ "8 PM \u2013 12 AM"),
new DateTest(0, 10, 9, 20, 0, 0, 10, 10, 0, 0,
DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_CAP_MIDNIGHT | DateUtils.FORMAT_ABBREV_ALL,
- "8pm \u2013 Midnight"),
+ "8 PM \u2013 12 AM"),
new DateTest(0, 10, 9, 0, 0, 0, 10, 10, 0, 0,
- DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "12am \u2013 midnight"),
+ DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL, "Nov 9, 12 AM \u2013 Nov 10, 12 AM"),
new DateTest(0, 10, 9, 0, 0, 0, 10, 10, 0, 0,
DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR | DateUtils.FORMAT_ABBREV_ALL,
- "00:00 \u2013 00:00"),
+ "Nov 9, 00:00 \u2013 Nov 10, 00:00"),
new DateTest(0, 10, 9, 0, 0, 0, 10, 10, 0, 0,
DateUtils.FORMAT_UTC | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL, "Nov 9"),
new DateTest(0, 10, 9, 0, 0, 0, 10, 10, 0, 0,
@@ -143,19 +143,19 @@ public class FormatDateRangeTest extends AndroidTestCase {
DateUtils.FORMAT_UTC | DateUtils.FORMAT_ABBREV_ALL, "Dec 29, 2007 \u2013 Jan 1, 2008"),
new DateTest(2007, 11, 29, 8, 0, 2008, 0, 2, 17, 0,
DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL,
- "Dec 29, 2007, 8am \u2013 Jan 2, 2008, 5pm"),
+ "Dec 29, 2007, 8 AM \u2013 Jan 2, 2008, 5 PM"),
new DateTest(0, 10, 9, 8, 0, 0, 10, 11, 17, 0,
DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL,
- "Nov 9, 8am \u2013 Nov 11, 5pm"),
+ "Nov 9, 8 AM \u2013 Nov 11, 5 PM"),
new DateTest(2007, 10, 9, 8, 0, 2007, 10, 11, 17, 0,
DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_ALL,
- "Fri, Nov 9, 2007 \u2013 Sun, Nov 11, 2007"),
+ "Fri, Nov 9 \u2013 Sun, Nov 11, 2007"),
new DateTest(2007, 10, 9, 8, 0, 2007, 10, 11, 17, 0,
DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_ALL,
- "Fri, Nov 9, 2007, 8am \u2013 Sun, Nov 11, 2007, 5pm"),
+ "Fri, Nov 9, 2007, 8 AM \u2013 Sun, Nov 11, 2007, 5 PM"),
new DateTest(2007, 11, 3, 13, 0, 2007, 11, 3, 14, 0,
DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR,
- "1:00PM \u2013 2:00PM, December 3, 2007"),
+ "December 3, 2007, 1:00 \u2013 2:00 PM"),
// Tests that FORMAT_SHOW_YEAR takes precedence over FORMAT_NO_YEAR:
new DateTest(2007, 11, 3, 13, 0, 2007, 11, 3, 13, 0,
DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_NO_YEAR,
diff --git a/tests/src/com/android/calendar/UtilsTests.java b/tests/src/com/android/calendar/UtilsTests.java
index 2a2bfbac..bf501d9d 100644
--- a/tests/src/com/android/calendar/UtilsTests.java
+++ b/tests/src/com/android/calendar/UtilsTests.java
@@ -190,13 +190,6 @@ public class UtilsTests extends TestCase {
@Smoke
@SmallTest
- public void testCheckForDuplicateNames() {
- Utils.checkForDuplicateNames(mIsDuplicateName, mDuplicateNameCursor, NAME_COLUMN);
- assertEquals(mIsDuplicateNameExpected, mIsDuplicateName);
- }
-
- @Smoke
- @SmallTest
public void testGetWeeksSinceEpochFromJulianDay() {
for (int i = 0; i < JULIAN_DAYS.length; i++) {
assertEquals(EXPECTED_WEEK_MONDAY_START[i],
@@ -217,20 +210,6 @@ public class UtilsTests extends TestCase {
}
}
- @Smoke
- @SmallTest
- public void testEquals() {
- assertTrue(Utils.equals(null, null));
- assertFalse(Utils.equals("", null));
- assertFalse(Utils.equals(null, ""));
- assertTrue(Utils.equals("",""));
-
- Integer int1 = new Integer(1);
- Integer int2 = new Integer(1);
- assertTrue(Utils.equals(int1, int2));
- }
-
-
// Helper function to create test events for BusyBits testing
Event buildTestEvent(int startTime, int endTime, boolean allDay, int startDay, int endDay) {
Event e = new Event();
@@ -244,263 +223,6 @@ public class UtilsTests extends TestCase {
return e;
}
- @Smoke
- @SmallTest
- public void testCreateBusyBitSegments() {
-
- /* ArrayList<Event> events = new ArrayList<Event>();
-
- // Test cases that should return null
- // Empty events list
- assertEquals(null, Utils.createBusyBitSegments(10, 30, 100, 200, 0, events));
- // No events list
- assertEquals(null, Utils.createBusyBitSegments(10, 30, 100, 200, 0, null));
-
- events.add(buildTestEvent(100, 130, false, 1, 1));
- events.add(buildTestEvent(1000, 1030, false, 1, 1));
- // Illegal pixel positions
- assertEquals(null, Utils.createBusyBitSegments(30, 10, 100, 200, 1, events));
- // Illegal start and end times
- assertEquals(null, Utils.createBusyBitSegments(10, 30, 200, 100, 1, events));
- assertEquals(null, Utils.createBusyBitSegments(10, 30, -10, 100, 1, events));
- assertEquals(null, Utils.createBusyBitSegments(10, 30, 24 * 60 + 100, 24 * 60 + 200, 1,
- events));
- assertEquals(null, Utils.createBusyBitSegments(10, 30, 200, 24 * 60 + 100, 1, events));
- assertEquals(null, Utils.createBusyBitSegments(10, 30, 200, -100, 1, events));
- // No Events in time frame
- assertEquals(null, Utils.createBusyBitSegments(10, 30, 500, 900, 1, events));
-
- // Test event that spans over the day
- events.clear();
- events.add(buildTestEvent(100, 300, false, 1, 5));
- ArrayList<BusyBitsSegment> segments = new ArrayList<BusyBitsSegment>();
- assertEquals(null, Utils.createBusyBitSegments(0, 250, 200, 1200, 3, events));
-
- // test zero times events, events that are partially in the time span
- // and all day events
- events.clear();
- events.add(buildTestEvent(100, 300, false, 1, 1));
- events.add(buildTestEvent(1100, 1300, false, 1, 1));
- events.add(buildTestEvent(500, 600, true, 1, 1));
- events.add(buildTestEvent(700, 700, false, 1, 1));
- segments.clear();
- segments.add(new BusyBitsSegment(0, 10, false));
- segments.add(new BusyBitsSegment(90, 100, false));
- assertEquals(segments, Utils.createBusyBitSegments(0, 100, 200, 1200, 1, events));
-
- // Test event that spans over 2 days but start and end time do not
- // overlap fully with tested time span
-
- events.clear();
- events.add(buildTestEvent(23 * 60, 120, false, 1, 2));
- segments.clear();
- segments.add(new BusyBitsSegment(0, 120, false));
- assertEquals(segments, Utils.createBusyBitSegments(0, 240, 60, 180, 2, events));
-
- // Test overlapped events (two draw sizes)
- events.clear();
- events.add(buildTestEvent(10, 200, false, 1, 1));
- events.add(buildTestEvent(150, 250, false, 1, 1));
- events.add(buildTestEvent(150, 250, false, 1, 1));
- events.add(buildTestEvent(200, 400, false, 1, 1));
- events.add(buildTestEvent(500, 700, false, 1, 1));
- events.add(buildTestEvent(550, 600, false, 1, 1));
- events.add(buildTestEvent(550, 580, false, 1, 1));
- events.add(buildTestEvent(560, 570, false, 1, 1));
- events.add(buildTestEvent(600, 700, false, 1, 1));
- events.add(buildTestEvent(620, 700, false, 1, 1));
- events.add(buildTestEvent(650, 700, false, 1, 1));
- events.add(buildTestEvent(800, 900, false, 1, 1));
- events.add(buildTestEvent(800, 900, false, 1, 1));
- events.add(buildTestEvent(800, 850, false, 1, 1));
- events.add(buildTestEvent(1000, 1200, false, 1, 1));
- events.add(buildTestEvent(1000, 1200, false, 1, 1));
- segments.clear();
- segments.add(new BusyBitsSegment(100, 149, false));
- segments.add(new BusyBitsSegment(150, 250, true));
- segments.add(new BusyBitsSegment(251, 400, false));
- segments.add(new BusyBitsSegment(500, 549, false));
- segments.add(new BusyBitsSegment(550, 700, true));
- segments.add(new BusyBitsSegment(800, 900, true));
- segments.add(new BusyBitsSegment(1000, 1100, true));
- assertEquals(segments, Utils.createBusyBitSegments(100, 1100, 100, 1100, 1, events));
- segments.clear();
- segments.add(new BusyBitsSegment(100, 111, false));
- segments.add(new BusyBitsSegment(112, 137, true));
- segments.add(new BusyBitsSegment(138, 175, false));
- segments.add(new BusyBitsSegment(200, 211, false));
- segments.add(new BusyBitsSegment(212, 250, true));
- segments.add(new BusyBitsSegment(275, 300, true));
- segments.add(new BusyBitsSegment(325, 350, true));
- assertEquals(segments, Utils.createBusyBitSegments(100, 350, 100, 1100, 1, events));
-*/
- }
-
- /**
- * Tests the findNanpPhoneNumbers function.
- */
- @SmallTest
- public void testFindNanpPhoneNumber() {
- final String[] NO_NUMBERS = new String[] {};
-
- findPhoneNumber("", NO_NUMBERS);
- findPhoneNumber(" ", NO_NUMBERS);
- findPhoneNumber("123", NO_NUMBERS);
- findPhoneNumber("how much wood", NO_NUMBERS);
- findPhoneNumber("abc1-650-555-1212", NO_NUMBERS);
- findPhoneNumber("abc 5551212 def", new String[] { "5551212" });
- findPhoneNumber("1234567", NO_NUMBERS);
- findPhoneNumber(" 2345678 ", new String[] { "2345678" });
- findPhoneNumber("1234567890", NO_NUMBERS);
- findPhoneNumber("12345678901", new String[] { "12345678901" });
- findPhoneNumber("123456789012", NO_NUMBERS);
- findPhoneNumber("+1-555-1212", NO_NUMBERS);
- findPhoneNumber("+1 (650) 555-1212", new String[] { "+1 (650) 555-1212" });
- findPhoneNumber("(650) 555-1212, (650) 555-1213",
- new String[] { "(650) 555-1212", "(650) 555-1213" });
- findPhoneNumber("Call 555-1212, 555-1213 and also 555-1214.",
- new String[] { "555-1212", "555-1213", "555-1214." });
- findPhoneNumber("555-1212,555-1213,555-1214", new String[] { "555-1212" });
- findPhoneNumber("123 (650) 555-1212", new String[] { "(650) 555-1212" });
- findPhoneNumber("1-650-555-1212", new String[] { "1-650-555-1212" });
- findPhoneNumber("1650-555-1212", new String[] { "1650-555-1212" });
- findPhoneNumber("1650 555-1212", new String[] { "1650 555-1212" });
- findPhoneNumber("1650/555-1212", NO_NUMBERS);
- findPhoneNumber("1650-555 1212", NO_NUMBERS);
- findPhoneNumber("8-650-555-1212", NO_NUMBERS);
- findPhoneNumber("8 650-555-1212", new String[] { "650-555-1212" });
- findPhoneNumber("650.555.1212", new String[] { "650.555.1212" });
- findPhoneNumber(" *#650.555.1212#*!", new String[] { "*#650.555.1212#*" });
- findPhoneNumber("555.1212", new String[] { "555.1212" });
- findPhoneNumber("6505551212 x123, 555-1212", new String[] { "6505551212", "555-1212" });
- findPhoneNumber("6505551212x123", new String[] { "6505551212" });
- findPhoneNumber("http://example.com/6505551212/", NO_NUMBERS);
- findPhoneNumber("Mountain View, CA 94043 (650) 555-1212", new String[]{ "(650) 555-1212" });
- findPhoneNumber("New York, NY 10001-0001", NO_NUMBERS);
- }
-
- /**
- * Finds the numbers in a block of text, and checks to see if the positions of the numbers
- * match the expected values.
- *
- * @param text The text to search.
- * @param matches Pairs of start/end positions.
- */
- private static void findPhoneNumber(String text, String[] matches) {
- int[] results = Utils.findNanpPhoneNumbers(text);
-
- assertEquals(0, results.length % 2);
-
- if (results.length / 2 != matches.length) {
- fail("Text '" + text + "': expected " + matches.length
- + " matches, found " + results.length / 2);
- }
-
- for (int i = 0; i < results.length / 2; i++) {
- CharSequence seq = text.subSequence(results[i*2], results[i*2 + 1]);
- assertEquals(matches[i], seq);
- }
- }
-
- /**
- * Tests the linkify section of event locations.
- */
- @SmallTest
- public void testExtendedLinkify() {
- final URLSpan[] NO_LINKS = new URLSpan[] {};
- URLSpan span_tel01 = new URLSpan("tel:6505551234");
- URLSpan span_tel02 = new URLSpan("tel:5555678");
- URLSpan span_tel03 = new URLSpan("tel:+16505551234");
- URLSpan span_tel04 = new URLSpan("tel:16505551234");
- URLSpan span_web = new URLSpan("http://www.google.com");
- URLSpan span_geo01 =
- new URLSpan("geo:0,0?q=1600+Amphitheatre+Parkway%2C+Mountain+View+CA+94043");
- URLSpan span_geo02 =
- new URLSpan("geo:0,0?q=37.422081°, -122.084576°");
- URLSpan span_geo03 =
- new URLSpan("geo:0,0?q=37.422081,-122.084576");
- URLSpan span_geo04 =
- new URLSpan("geo:0,0?q=+37°25'19.49\", -122°5'4.47\"");
- URLSpan span_geo05 =
- new URLSpan("geo:0,0?q=37°25'19.49\"N, 122°5'4.47\"W");
- URLSpan span_geo06 =
- new URLSpan("geo:0,0?q=N 37° 25' 19.49\", W 122° 5' 4.47\"");
- URLSpan span_geo07 = new URLSpan("geo:0,0?q=non-specified address");
-
-
- // First test without the last-ditch geo attempt.
- // Phone spans.
- findLinks("", NO_LINKS, false);
- findLinks("(650) 555-1234", new URLSpan[]{span_tel01}, false);
- findLinks("94043", NO_LINKS, false);
- findLinks("123456789012", NO_LINKS, false);
- findLinks("+1 (650) 555-1234", new URLSpan[]{span_tel03}, false);
- findLinks("(650) 555 1234", new URLSpan[]{span_tel01}, false);
- findLinks("1-650-555-1234", new URLSpan[]{span_tel04}, false);
- findLinks("*#650.555.1234#*!", new URLSpan[]{span_tel01}, false);
- findLinks("555.5678", new URLSpan[]{span_tel02}, false);
-
- // Web spans.
- findLinks("http://www.google.com", new URLSpan[]{span_web}, false);
-
- // Geo spans.
- findLinks("1600 Amphitheatre Parkway, Mountain View CA 94043",
- new URLSpan[]{span_geo01}, false);
- findLinks("37.422081°, -122.084576°", new URLSpan[]{span_geo02}, false);
- findLinks("37.422081,-122.084576", new URLSpan[]{span_geo03}, false);
- findLinks("+37°25'19.49\", -122°5'4.47\"", new URLSpan[]{span_geo04}, false);
- findLinks("37°25'19.49\"N, 122°5'4.47\"W", new URLSpan[]{span_geo05}, false);
- findLinks("N 37° 25' 19.49\", W 122° 5' 4.47\"", new URLSpan[]{span_geo06}, false);
-
- // Multiple spans.
- findLinks("(650) 555-1234 1600 Amphitheatre Parkway, Mountain View CA 94043",
- new URLSpan[]{span_tel01, span_geo01}, false);
- findLinks("(650) 555-1234, 555-5678", new URLSpan[]{span_tel01, span_tel02}, false);
-
-
- // Now test using the last-ditch geo attempt.
- findLinks("", NO_LINKS, true);
- findLinks("(650) 555-1234", new URLSpan[]{span_tel01}, true);
- findLinks("http://www.google.com", new URLSpan[]{span_web}, true);
- findLinks("1600 Amphitheatre Parkway, Mountain View CA 94043",
- new URLSpan[]{span_geo01}, true);
- findLinks("37.422081°, -122.084576°", new URLSpan[]{span_geo02}, true);
- findLinks("37.422081,-122.084576", new URLSpan[]{span_geo03}, true);
- findLinks("+37°25'19.49\", -122°5'4.47\"", new URLSpan[]{span_geo04}, true);
- findLinks("37°25'19.49\"N, 122°5'4.47\"W", new URLSpan[]{span_geo05}, true);
- findLinks("N 37° 25' 19.49\", W 122° 5' 4.47\"", new URLSpan[]{span_geo06}, true);
- findLinks("non-specified address", new URLSpan[]{span_geo07}, true);
- }
-
- private static void findLinks(String text, URLSpan[] matches, boolean lastDitchGeo) {
- Spannable spanText = Utils.extendedLinkify(text, lastDitchGeo);
- URLSpan[] spansFound = spanText.getSpans(0, spanText.length(), URLSpan.class);
- assertEquals(matches.length, spansFound.length);
-
- // Make sure the expected matches list of URLs is the same as that returned by linkify.
- ArrayList<URLSpan> matchesArrayList = new ArrayList<URLSpan>(Arrays.asList(matches));
- for (URLSpan spanFound : spansFound) {
- Iterator<URLSpan> matchesIt = matchesArrayList.iterator();
- boolean removed = false;
- while (matchesIt.hasNext()) {
- URLSpan match = matchesIt.next();
- if (match.getURL().equals(spanFound.getURL())) {
- matchesIt.remove();
- removed = true;
- break;
- }
- }
- if (!removed) {
- // If a match was not found for the current spanFound, the lists aren't equal.
- fail("No match found for span: "+spanFound.getURL());
- }
- }
-
- // As a sanity check, ensure the matches list is empty, as each item should have been
- // removed by going through the spans returned by linkify.
- assertTrue(matchesArrayList.isEmpty());
- }
-
@SmallTest
public void testGetDisplayedDatetime_differentYear() {
// 4/12/2000 5pm - 4/12/2000 6pm
@@ -508,14 +230,14 @@ public class UtilsTests extends TestCase {
long end = createTimeInMillis(0, 0, 18, 12, 3, 2000);
String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
false, dbUtils.getContext());
- assertEquals("Wednesday, April 12, 2000, 5:00PM \u2013 6:00PM", result);
+ assertEquals("Wednesday, April 12, 2000, 5:00 \u2013 6:00 PM", result);
// 12/31/2012 5pm - 1/1/2013 6pm
start = createTimeInMillis(0, 0, 17, 31, 11, 2012);
end = createTimeInMillis(0, 0, 18, 1, 0, 2013);
result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
false, dbUtils.getContext());
- assertEquals("Mon, Dec 31, 2012, 5:00PM – Tue, Jan 1, 2013, 6:00PM", result);
+ assertEquals("Mon, Dec 31, 2012, 5:00 PM – Tue, Jan 1, 2013, 6:00 PM", result);
}
@SmallTest
@@ -525,7 +247,7 @@ public class UtilsTests extends TestCase {
long end = createTimeInMillis(0, 0, 18, 12, 3, 2012);
String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
false, dbUtils.getContext());
- assertEquals("Thursday, April 12, 2012, 5:00PM \u2013 6:00PM", result);
+ assertEquals("Thursday, April 12, 2012, 5:00 \u2013 6:00 PM", result);
}
@SmallTest
@@ -535,7 +257,7 @@ public class UtilsTests extends TestCase {
long end = createTimeInMillis(0, 0, 18, NOW_DAY, NOW_MONTH, NOW_YEAR);
String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
false, dbUtils.getContext());
- assertEquals("Today at 5:00PM \u2013 6:00PM", result);
+ assertEquals("Today at 5:00 \u2013 6:00 PM", result);
}
@SmallTest
@@ -545,7 +267,7 @@ public class UtilsTests extends TestCase {
long end = createTimeInMillis(0, 0, 0, NOW_DAY + 1, NOW_MONTH, NOW_YEAR);
String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
false, dbUtils.getContext());
- assertEquals("Today at 5:00PM \u2013 midnight", result);
+ assertEquals("Today at 5:00 PM \u2013 12:00 AM", result);
}
@SmallTest
@@ -555,7 +277,7 @@ public class UtilsTests extends TestCase {
long end = createTimeInMillis(0, 59, 23, NOW_DAY + 1, NOW_MONTH, NOW_YEAR);
String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
false, dbUtils.getContext());
- assertEquals("Tomorrow at 12:01AM \u2013 11:59PM", result);
+ assertEquals("Tomorrow at 12:01 AM \u2013 11:59 PM", result);
}
@SmallTest
@@ -565,7 +287,7 @@ public class UtilsTests extends TestCase {
long end = createTimeInMillis(0, 0, 18, 9, 3, 2012);
String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
false, dbUtils.getContext());
- assertEquals("Monday, April 9, 2012, 5:00PM \u2013 6:00PM", result);
+ assertEquals("Monday, April 9, 2012, 5:00 \u2013 6:00 PM", result);
}
@SmallTest
@@ -575,7 +297,7 @@ public class UtilsTests extends TestCase {
long end = createTimeInMillis(0, 1, 0, NOW_DAY + 1, NOW_MONTH, NOW_YEAR);
String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
false, dbUtils.getContext());
- assertEquals("Tue, Apr 10, 2012, 12:01AM \u2013 Wed, Apr 11, 2012, 12:01AM", result);
+ assertEquals("Tue, Apr 10, 2012, 12:01 AM \u2013 Wed, Apr 11, 2012, 12:01 AM", result);
}
@SmallTest
@@ -605,7 +327,7 @@ public class UtilsTests extends TestCase {
long end = createTimeInMillis(0, 0, 0, NOW_DAY + 3, NOW_MONTH, NOW_YEAR, Time.TIMEZONE_UTC);
String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
true, dbUtils.getContext());
- assertEquals("Tuesday, April 10, 2012 \u2013 Thursday, April 12, 2012", result);
+ assertEquals("Tuesday, April 10 \u2013 Thursday, April 12, 2012", result);
}
@SmallTest
@@ -619,7 +341,7 @@ public class UtilsTests extends TestCase {
long end = createTimeInMillis(0, 0, 18, 12, 3, 2012, eventTz);
String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, localTz, false,
dbUtils.getContext());
- assertEquals("Thursday, April 12, 2012, 8:00PM \u2013 9:00PM", result);
+ assertEquals("Thursday, April 12, 2012, 8:00 \u2013 9:00 PM", result);
}
@SmallTest
diff --git a/tests/src/com/android/calendar/alerts/AlarmSchedulerTest.java b/tests/src/com/android/calendar/alerts/AlarmSchedulerTest.java
deleted file mode 100644
index 1202e102..00000000
--- a/tests/src/com/android/calendar/alerts/AlarmSchedulerTest.java
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright (C) 2012 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.alerts;
-
-import android.app.AlarmManager;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.net.Uri;
-import android.provider.CalendarContract;
-import android.provider.CalendarContract.Instances;
-import android.provider.CalendarContract.Reminders;
-import android.test.AndroidTestCase;
-import android.test.IsolatedContext;
-import android.test.mock.MockContentProvider;
-import android.test.mock.MockContentResolver;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-import android.util.Log;
-
-import junit.framework.Assert;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-
-@SmallTest
-public class AlarmSchedulerTest extends AndroidTestCase {
- private static final int BATCH_SIZE = 50;
- private MockProvider mMockProvider;
- private MockAlarmManager mMockAlarmManager;
- private IsolatedContext mIsolatedContext;
-
- /**
- * A helper class to mock query results from the test data.
- */
- private static class MockProvider extends MockContentProvider {
- private ArrayList<EventInfo> mEvents = new ArrayList<EventInfo>();
- private ArrayList<String> mExpectedRemindersQueries = new ArrayList<String>();
- private int mCurrentReminderQueryIndex = 0;
-
- /**
- * Contains info for a test event and its reminder.
- */
- private static class EventInfo {
- long mEventId;
- long mBegin;
- boolean mAllDay;
- int mReminderMinutes;
-
- public EventInfo(long eventId, boolean allDay, long begin, int reminderMinutes) {
- mEventId = eventId;
- mAllDay = allDay;
- mBegin = begin;
- mReminderMinutes = reminderMinutes;
- }
-
- }
-
- /**
- * Adds event/reminder data for testing. These will always be returned in the mocked
- * query result cursors.
- */
- void addEventInfo(long eventId, boolean allDay, long begin, int reminderMinutes) {
- mEvents.add(new EventInfo(eventId, allDay, begin, reminderMinutes));
- }
-
- private MatrixCursor getInstancesCursor() {
- MatrixCursor instancesCursor = new MatrixCursor(AlarmScheduler.INSTANCES_PROJECTION);
- int i = 0;
- HashSet<Long> eventIds = new HashSet<Long>();
- for (EventInfo event : mEvents) {
- if (!eventIds.contains(event.mEventId)) {
- Object[] ca = {
- event.mEventId,
- event.mBegin,
- event.mAllDay ? 1 : 0,
- };
- instancesCursor.addRow(ca);
- eventIds.add(event.mEventId);
- }
- }
- return instancesCursor;
- }
-
- private MatrixCursor getRemindersCursor() {
- MatrixCursor remindersCursor = new MatrixCursor(AlarmScheduler.REMINDERS_PROJECTION);
- int i = 0;
- for (EventInfo event : mEvents) {
- Object[] ca = {
- event.mEventId,
- event.mReminderMinutes,
- 1,
- };
- remindersCursor.addRow(ca);
- }
- return remindersCursor;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- if (uri.toString().startsWith(Instances.CONTENT_URI.toString())) {
- return getInstancesCursor();
- } else if (Reminders.CONTENT_URI.equals(uri)) {
- if (mExpectedRemindersQueries.size() > 0) {
- if (mExpectedRemindersQueries.size() <= mCurrentReminderQueryIndex ||
- !mExpectedRemindersQueries.get(mCurrentReminderQueryIndex).equals(
- selection)) {
- String msg = "Reminders query not as expected.\n";
- msg += " Expected:";
- msg += Arrays.deepToString(mExpectedRemindersQueries.toArray());
- msg += "\n Got in position " + mCurrentReminderQueryIndex + ": ";
- msg += selection;
- fail(msg);
- }
- mCurrentReminderQueryIndex++;
- }
- return getRemindersCursor();
- } else {
- return super.query(uri, projection, selection, selectionArgs, sortOrder);
- }
- }
-
- /**
- * Optionally set up expectation for the reminders query selection.
- */
- public void addExpectedRemindersQuery(String expectedRemindersQuery) {
- this.mExpectedRemindersQueries.add(expectedRemindersQuery);
- }
- }
-
- /**
- * Expect an alarm for the specified time.
- */
- private void expectAlarmAt(long millis) {
- // AlarmScheduler adds a slight delay to the alarm so account for that here.
- mMockAlarmManager.expectAlarmTime(AlarmManager.RTC_WAKEUP,
- millis + AlarmScheduler.ALARM_DELAY_MS);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mMockProvider = new MockProvider();
- mMockAlarmManager = new MockAlarmManager(mContext);
- MockContentResolver mockResolver = new MockContentResolver();
- mockResolver.addProvider(CalendarContract.AUTHORITY, mMockProvider);
- mIsolatedContext = new IsolatedContext(mockResolver, mContext);
- }
-
- public void testNoEvents() {
- AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager,
- BATCH_SIZE, System.currentTimeMillis());
- assertFalse(mMockAlarmManager.isAlarmSet());
- }
-
- public void testNonAllDayEvent() {
- // Set up mock test data.
- long currentMillis = System.currentTimeMillis();
- long startMillis = currentMillis + DateUtils.HOUR_IN_MILLIS;
- int reminderMin = 10;
- mMockProvider.addEventInfo(1, false, startMillis, reminderMin);
- expectAlarmAt(startMillis - reminderMin * DateUtils.MINUTE_IN_MILLIS);
-
- // Invoke scheduleNextAlarm and verify alarm was set at the expected time.
- AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
- currentMillis);
- assertTrue(mMockAlarmManager.isAlarmSet());
- }
-
- public void testAllDayEvent() {
- // Set up mock allday data.
- long startMillisUtc = Utils.createTimeInMillis(0, 0, 0, 1, 5, 2012, Time.TIMEZONE_UTC);
- long startMillisLocal = Utils.createTimeInMillis(0, 0, 0, 1, 5, 2012,
- Time.getCurrentTimezone());
- long currentMillis = startMillisLocal - DateUtils.DAY_IN_MILLIS;
- int reminderMin = 15;
- mMockProvider.addEventInfo(1, true, startMillisUtc, reminderMin);
- expectAlarmAt(startMillisLocal - reminderMin * DateUtils.MINUTE_IN_MILLIS);
-
- // Invoke scheduleNextAlarm and verify alarm was set at the expected time.
- AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
- currentMillis);
- assertTrue(mMockAlarmManager.isAlarmSet());
- }
-
- public void testAllDayAndNonAllDayEvents() {
- // Set up mock test data.
- long startMillisUtc = Utils.createTimeInMillis(0, 0, 0, 1, 5, 2012, Time.TIMEZONE_UTC);
- long startMillisLocal = Utils.createTimeInMillis(0, 0, 0, 1, 5, 2012,
- Time.getCurrentTimezone());
- long currentMillis = startMillisLocal - DateUtils.DAY_IN_MILLIS;
- mMockProvider.addEventInfo(1, true, startMillisUtc, 15);
- mMockProvider.addEventInfo(1, false, startMillisLocal, 10);
- expectAlarmAt(startMillisLocal - 15 * DateUtils.MINUTE_IN_MILLIS);
-
- // Invoke scheduleNextAlarm and verify alarm was set at the expected time.
- AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
- currentMillis);
- assertTrue(mMockAlarmManager.isAlarmSet());
- }
-
- public void testExpiredReminder() {
- // Set up mock test data.
- long currentMillis = System.currentTimeMillis();
- long startMillis = currentMillis + DateUtils.HOUR_IN_MILLIS;
- int reminderMin = 61;
- mMockProvider.addEventInfo(1, false, startMillis, reminderMin);
-
- // Invoke scheduleNextAlarm and verify no alarm was set.
- AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
- currentMillis);
- assertFalse(mMockAlarmManager.isAlarmSet());
- }
-
- public void testAlarmMax() {
- // Set up mock test data for a reminder greater than 1 day in the future.
- // This will be maxed out to 1 day out.
- long currentMillis = System.currentTimeMillis();
- long startMillis = currentMillis + DateUtils.DAY_IN_MILLIS * 3;
- int reminderMin = (int) DateUtils.DAY_IN_MILLIS / (1000 * 60);
- mMockProvider.addEventInfo(1, false, startMillis, reminderMin);
- expectAlarmAt(currentMillis + DateUtils.DAY_IN_MILLIS);
-
- // Invoke scheduleNextAlarm and verify alarm was set at the expected time.
- AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
- currentMillis);
- assertTrue(mMockAlarmManager.isAlarmSet());
- }
-
- public void testMultipleEvents() {
- // Set up multiple events where a later event time has an earlier reminder time.
- long currentMillis = System.currentTimeMillis();
- mMockProvider.addEventInfo(1, false, currentMillis + DateUtils.DAY_IN_MILLIS, 0);
- mMockProvider.addEventInfo(2, false, currentMillis + DateUtils.MINUTE_IN_MILLIS * 60, 45);
- mMockProvider.addEventInfo(3, false, currentMillis + DateUtils.MINUTE_IN_MILLIS * 30, 10);
-
- // Expect event 2's reminder.
- expectAlarmAt(currentMillis + DateUtils.MINUTE_IN_MILLIS * 15);
-
- // Invoke scheduleNextAlarm and verify alarm was set at the expected time.
- AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
- currentMillis);
- assertTrue(mMockAlarmManager.isAlarmSet());
- }
-
- public void testRecurringEvents() {
- long currentMillis = System.currentTimeMillis();
-
- // Event in 3 days, with a 2 day reminder
- mMockProvider.addEventInfo(1, false, currentMillis + DateUtils.DAY_IN_MILLIS * 3,
- (int) DateUtils.DAY_IN_MILLIS * 2 / (1000 * 60) /* 2 day reminder */);
- // Event for tomorrow, with a 2 day reminder
- mMockProvider.addEventInfo(1, false, currentMillis + DateUtils.DAY_IN_MILLIS,
- (int) DateUtils.DAY_IN_MILLIS * 2 / (1000 * 60) /* 2 day reminder */);
-
- // Expect the reminder for the top event because the reminder time for the bottom
- // one already passed.
- expectAlarmAt(currentMillis + DateUtils.DAY_IN_MILLIS);
-
- // Invoke scheduleNextAlarm and verify alarm was set at the expected time.
- AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
- currentMillis);
- assertTrue(mMockAlarmManager.isAlarmSet());
- }
-
- public void testMultipleRemindersForEvent() {
- // Set up mock test data.
- long currentMillis = System.currentTimeMillis();
- mMockProvider.addEventInfo(1, false, currentMillis + DateUtils.DAY_IN_MILLIS, 10);
- mMockProvider.addEventInfo(1, false, currentMillis + DateUtils.DAY_IN_MILLIS, 20);
- mMockProvider.addEventInfo(1, false, currentMillis + DateUtils.DAY_IN_MILLIS, 15);
-
- // Expect earliest reminder.
- expectAlarmAt(currentMillis + DateUtils.DAY_IN_MILLIS - DateUtils.MINUTE_IN_MILLIS * 20);
-
- // Invoke scheduleNextAlarm and verify alarm was set at the expected time.
- AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
- currentMillis);
- assertTrue(mMockAlarmManager.isAlarmSet());
- }
-
- public void testLargeBatch() {
- // Add enough events to require several batches.
- long currentMillis = System.currentTimeMillis();
- int batchSize = 5;
- for (int i = 19; i > 0; i--) {
- mMockProvider.addEventInfo(i, false, currentMillis + DateUtils.HOUR_IN_MILLIS * i,
- 10);
- }
-
- // Set up expectations for the batch queries.
- expectAlarmAt(currentMillis + DateUtils.MINUTE_IN_MILLIS * 50);
- mMockProvider.addExpectedRemindersQuery("method=1 AND event_id IN (19,18,17,16,15)");
- mMockProvider.addExpectedRemindersQuery("method=1 AND event_id IN (14,13,12,11,10)");
- mMockProvider.addExpectedRemindersQuery("method=1 AND event_id IN (9,8,7,6,5)");
- mMockProvider.addExpectedRemindersQuery("method=1 AND event_id IN (4,3,2,1)");
-
- // Invoke scheduleNextAlarm and verify alarm and reminder query batches.
- AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, batchSize,
- currentMillis);
- }
-}
diff --git a/tests/src/com/android/calendar/alerts/AlertServiceTest.java b/tests/src/com/android/calendar/alerts/AlertServiceTest.java
deleted file mode 100644
index 52da47c4..00000000
--- a/tests/src/com/android/calendar/alerts/AlertServiceTest.java
+++ /dev/null
@@ -1,1033 +0,0 @@
-/*
- * Copyright (C) 2012 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.alerts;
-
-import static android.app.Notification.PRIORITY_DEFAULT;
-import static android.app.Notification.PRIORITY_HIGH;
-import static android.app.Notification.PRIORITY_MIN;
-
-import android.app.AlarmManager;
-import android.content.SharedPreferences;
-import android.database.MatrixCursor;
-import android.provider.CalendarContract.Attendees;
-import android.provider.CalendarContract.CalendarAlerts;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Smoke;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-
-import com.android.calendar.GeneralPreferences;
-import com.android.calendar.alerts.AlertService.NotificationInfo;
-import com.android.calendar.alerts.AlertService.NotificationWrapper;
-
-import junit.framework.Assert;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Set;
-
-public class AlertServiceTest extends AndroidTestCase {
-
- class MockSharedPreferences implements SharedPreferences {
-
- private Boolean mVibrate;
- private String mRingtone;
- private Boolean mPopup;
-
- // Strict mode will fail if a preference key is queried more than once.
- private boolean mStrict = false;
-
- MockSharedPreferences() {
- this(false);
- }
-
- MockSharedPreferences(boolean strict) {
- super();
- init();
- this.mStrict = strict;
- }
-
- void init() {
- mVibrate = true;
- mRingtone = "/some/cool/ringtone";
- mPopup = true;
- }
-
- @Override
- public boolean contains(String key) {
- if (GeneralPreferences.KEY_ALERTS_VIBRATE.equals(key)) {
- return true;
- }
- return false;
- }
-
- @Override
- public boolean getBoolean(String key, boolean defValue) {
- if (GeneralPreferences.KEY_ALERTS_VIBRATE.equals(key)) {
- if (mVibrate == null) {
- Assert.fail(GeneralPreferences.KEY_ALERTS_VIBRATE
- + " fetched more than once.");
- }
- boolean val = mVibrate;
- if (mStrict) {
- mVibrate = null;
- }
- return val;
- }
- if (GeneralPreferences.KEY_ALERTS_POPUP.equals(key)) {
- if (mPopup == null) {
- Assert.fail(GeneralPreferences.KEY_ALERTS_POPUP + " fetched more than once.");
- }
- boolean val = mPopup;
- if (mStrict) {
- mPopup = null;
- }
- return val;
- }
- throw new IllegalArgumentException();
- }
-
- @Override
- public String getString(String key, String defValue) {
- if (GeneralPreferences.KEY_ALERTS_RINGTONE.equals(key)) {
- if (mRingtone == null) {
- Assert.fail(GeneralPreferences.KEY_ALERTS_RINGTONE
- + " fetched more than once.");
- }
- String val = mRingtone;
- if (mStrict) {
- mRingtone = null;
- }
- return val;
- }
- throw new IllegalArgumentException();
- }
-
- @Override
- public Map<String, ?> getAll() {
- throw new IllegalArgumentException();
- }
-
- @Override
- public Set<String> getStringSet(String key, Set<String> defValues) {
- throw new IllegalArgumentException();
- }
-
- @Override
- public int getInt(String key, int defValue) {
- throw new IllegalArgumentException();
- }
-
- @Override
- public long getLong(String key, long defValue) {
- throw new IllegalArgumentException();
- }
-
- @Override
- public float getFloat(String key, float defValue) {
- throw new IllegalArgumentException();
- }
-
- @Override
- public Editor edit() {
- throw new IllegalArgumentException();
- }
-
- @Override
- public void registerOnSharedPreferenceChangeListener(
- OnSharedPreferenceChangeListener listener) {
- throw new IllegalArgumentException();
- }
-
- @Override
- public void unregisterOnSharedPreferenceChangeListener(
- OnSharedPreferenceChangeListener listener) {
- throw new IllegalArgumentException();
- }
-
- }
-
- // Created these constants so the test cases are shorter
- public static final int SCHEDULED = CalendarAlerts.STATE_SCHEDULED;
- public static final int FIRED = CalendarAlerts.STATE_FIRED;
- public static final int DISMISSED = CalendarAlerts.STATE_DISMISSED;
-
- public static final int ACCEPTED = Attendees.ATTENDEE_STATUS_ACCEPTED;
- public static final int DECLINED = Attendees.ATTENDEE_STATUS_DECLINED;
- public static final int INVITED = Attendees.ATTENDEE_STATUS_INVITED;
- public static final int TENTATIVE = Attendees.ATTENDEE_STATUS_TENTATIVE;
-
- class NotificationInstance {
- int mAlertId;
- int[] mAlertIdsInDigest;
- int mPriority;
-
- public NotificationInstance(int alertId, int priority) {
- mAlertId = alertId;
- mPriority = priority;
- }
-
- public NotificationInstance(int[] alertIdsInDigest, int priority) {
- mAlertIdsInDigest = alertIdsInDigest;
- mPriority = priority;
- }
- }
-
- class Alert {
- long mEventId;
- int mAlertStatus;
- int mResponseStatus;
- int mAllDay;
- long mBegin;
- long mEnd;
- int mMinute;
- long mAlarmTime;
-
- public Alert(long eventId, int alertStatus, int responseStatus, int allDay, long begin,
- long end, int minute, long alarmTime) {
- mEventId = eventId;
- mAlertStatus = alertStatus;
- mResponseStatus = responseStatus;
- mAllDay = allDay;
- mBegin = begin;
- mEnd = end;
- mMinute = minute;
- mAlarmTime = alarmTime;
- }
-
- }
-
- class AlertsTable {
-
- ArrayList<Alert> mAlerts = new ArrayList<Alert>();
-
- int addAlertRow(long eventId, int alertStatus, int responseStatus, int allDay, long begin,
- long end, long alarmTime) {
- Alert a = new Alert(eventId, alertStatus, responseStatus, allDay, begin, end,
- 5 /* minute */, alarmTime);
- int id = mAlerts.size();
- mAlerts.add(a);
- return id;
- }
-
- public MatrixCursor getAlertCursor() {
- MatrixCursor alertCursor = new MatrixCursor(AlertService.ALERT_PROJECTION);
-
- int i = 0;
- for (Alert a : mAlerts) {
- Object[] ca = {
- i++,
- a.mEventId,
- a.mAlertStatus,
- "Title" + a.mEventId + " " + a.mMinute,
- "Loc" + a.mEventId,
- a.mResponseStatus,
- a.mAllDay,
- a.mAlarmTime > 0 ? a.mAlarmTime : a.mBegin - a.mMinute * 60 * 1000,
- a.mMinute,
- a.mBegin,
- a.mEnd,
- "Desc: " + a.mAlarmTime
- };
- alertCursor.addRow(ca);
- }
- return alertCursor;
- }
-
- }
-
- class NotificationTestManager extends NotificationMgr {
- // Expected notifications
- NotificationInstance[] mExpectedNotifications;
- NotificationWrapper[] mActualNotifications;
- boolean[] mCancelled;
-
- // CalendarAlerts table
- private ArrayList<Alert> mAlerts;
-
- public NotificationTestManager(ArrayList<Alert> alerts, int maxNotifications) {
- assertEquals(0, AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID);
- mAlerts = alerts;
- mExpectedNotifications = new NotificationInstance[maxNotifications + 1];
- mActualNotifications = new NotificationWrapper[mExpectedNotifications.length];
- mCancelled = new boolean[mExpectedNotifications.length];
- }
-
- public void expectTestNotification(int notificationId, int alertId, int highPriority) {
- mExpectedNotifications[notificationId] = new NotificationInstance(alertId,
- highPriority);
- }
-
- public void expectTestNotification(int notificationId, int[] alertIds, int priority) {
- mExpectedNotifications[notificationId] = new NotificationInstance(alertIds, priority);
- }
-
- private <T> boolean nullContents(T[] array) {
- for (T item : array) {
- if (item != null) {
- return false;
- }
- }
- return true;
- }
-
- public void validateNotificationsAndReset() {
- if (nullContents(mExpectedNotifications)) {
- return;
- }
-
- String debugStr = printActualNotifications();
- for (int id = 0; id < mActualNotifications.length; id++) {
- NotificationInstance expected = mExpectedNotifications[id];
- NotificationWrapper actual = mActualNotifications[id];
- if (expected == null) {
- assertNull("Received unexpected notificationId " + id + debugStr, actual);
- assertTrue("NotificationId " + id + " should have been cancelled." + debugStr,
- mCancelled[id]);
- } else {
- assertNotNull("Expected notificationId " + id + " but it was not posted."
- + debugStr, actual);
- assertFalse("NotificationId " + id + " should not have been cancelled."
- + debugStr, mCancelled[id]);
- assertEquals("Priority not as expected for notification " + id + debugStr,
- expected.mPriority, actual.mNotification.priority);
- if (expected.mAlertIdsInDigest == null) {
- Alert a = mAlerts.get(expected.mAlertId);
- assertEquals("Event ID not expected for notification " + id + debugStr,
- a.mEventId, actual.mEventId);
- assertEquals("Begin time not expected for notification " + id + debugStr,
- a.mBegin, actual.mBegin);
- assertEquals("End time not expected for notification " + id + debugStr,
- a.mEnd, actual.mEnd);
- } else {
- // Notification should be a digest.
- assertNotNull("Posted notification not a digest as expected." + debugStr,
- actual.mNw);
- assertEquals("Number of notifications in digest not as expected."
- + debugStr, expected.mAlertIdsInDigest.length, actual.mNw.size());
- for (int i = 0; i < actual.mNw.size(); i++) {
- Alert a = mAlerts.get(expected.mAlertIdsInDigest[i]);
- assertEquals("Digest item " + i + ": Event ID not as expected"
- + debugStr, a.mEventId, actual.mNw.get(i).mEventId);
- assertEquals("Digest item " + i + ": Begin time in digest not expected"
- + debugStr, a.mBegin, actual.mNw.get(i).mBegin);
- assertEquals("Digest item " + i + ": End time in digest not expected"
- + debugStr, a.mEnd, actual.mNw.get(i).mEnd);
- }
- }
- }
- }
-
- Arrays.fill(mCancelled, false);
- Arrays.fill(mExpectedNotifications, null);
- Arrays.fill(mActualNotifications, null);
- }
-
- private String printActualNotifications() {
- StringBuilder s = new StringBuilder();
- s.append("\n\nNotifications actually posted:\n");
- for (int i = mActualNotifications.length - 1; i >= 0; i--) {
- NotificationWrapper actual = mActualNotifications[i];
- if (actual == null) {
- continue;
- }
- s.append("Notification " + i + " -- ");
- s.append("priority:" + actual.mNotification.priority);
- if (actual.mNw == null) {
- s.append(", eventId:" + actual.mEventId);
- } else {
- s.append(", eventIds:{");
- for (int digestIndex = 0; digestIndex < actual.mNw.size(); digestIndex++) {
- s.append(actual.mNw.get(digestIndex).mEventId + ",");
- }
- s.append("}");
- }
- s.append("\n");
- }
- return s.toString();
- }
-
- ///////////////////////////////
- // NotificationMgr methods
- @Override
- public void cancel(int id) {
- assertTrue("id out of bound: " + id, 0 <= id);
- assertTrue("id out of bound: " + id, id < mCancelled.length);
- assertNull("id already used", mActualNotifications[id]);
- assertFalse("id already used", mCancelled[id]);
- mCancelled[id] = true;
- assertNull("Unexpected cancel for id " + id, mExpectedNotifications[id]);
- }
-
- @Override
- public void notify(int id, NotificationWrapper nw) {
- assertTrue("id out of bound: " + id, 0 <= id);
- assertTrue("id out of bound: " + id, id < mExpectedNotifications.length);
- assertNull("id already used: " + id, mActualNotifications[id]);
- mActualNotifications[id] = nw;
- }
- }
-
- // TODO
- // Catch updates of new state, notify time, and received time
- // Test ringer, vibrate,
- // Test intents, action email
-
- @Smoke
- @SmallTest
- public void testGenerateAlerts_none() {
- MockSharedPreferences prefs = new MockSharedPreferences();
- AlertsTable at = new AlertsTable();
- NotificationTestManager ntm = new NotificationTestManager(at.mAlerts,
- AlertService.MAX_NOTIFICATIONS);
-
- // Test no alert
- long currentTime = 1000000;
- AlertService.generateAlerts(mContext, ntm, new MockAlarmManager(mContext), prefs,
- at.getAlertCursor(), currentTime, AlertService.MAX_NOTIFICATIONS);
- ntm.validateNotificationsAndReset();
- }
-
- @Smoke
- @SmallTest
- public void testGenerateAlerts_single() {
- MockSharedPreferences prefs = new MockSharedPreferences();
- MockAlarmManager alarmMgr = new MockAlarmManager(mContext);
- AlertsTable at = new AlertsTable();
- NotificationTestManager ntm = new NotificationTestManager(at.mAlerts,
- AlertService.MAX_NOTIFICATIONS);
-
- int id = at.addAlertRow(100, SCHEDULED, ACCEPTED, 0 /* all day */, 1300000, 2300000, 0);
-
- // Test one up coming alert
- long currentTime = 1000000;
- ntm.expectTestNotification(1, id, PRIORITY_HIGH);
-
- AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(), currentTime,
- AlertService.MAX_NOTIFICATIONS);
- ntm.validateNotificationsAndReset(); // This wipes out notification
- // tests added so far
-
- // Test half way into an event
- currentTime = 2300000;
- ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID, id, PRIORITY_MIN);
-
- AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(), currentTime,
- AlertService.MAX_NOTIFICATIONS);
- ntm.validateNotificationsAndReset();
-
- // Test event ended
- currentTime = 4300000;
- ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID, id, PRIORITY_MIN);
-
- AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(), currentTime,
- AlertService.MAX_NOTIFICATIONS);
- ntm.validateNotificationsAndReset();
- }
-
- @SmallTest
- public void testGenerateAlerts_multiple() {
- int maxNotifications = 10;
- MockSharedPreferences prefs = new MockSharedPreferences();
- MockAlarmManager alarmMgr = new MockAlarmManager(mContext);
- AlertsTable at = new AlertsTable();
- NotificationTestManager ntm = new NotificationTestManager(at.mAlerts, maxNotifications);
-
- // Current time - 5:00
- long currentTime = createTimeInMillis(5, 0);
-
- // Set up future alerts. The real query implementation sorts by descending start
- // time so simulate that here with our order of adds to AlertsTable.
- int id9 = at.addAlertRow(9, SCHEDULED, ACCEPTED, 0, createTimeInMillis(9, 0),
- createTimeInMillis(10, 0), 0);
- int id8 = at.addAlertRow(8, SCHEDULED, ACCEPTED, 0, createTimeInMillis(8, 0),
- createTimeInMillis(9, 0), 0);
- int id7 = at.addAlertRow(7, SCHEDULED, ACCEPTED, 0, createTimeInMillis(7, 0),
- createTimeInMillis(8, 0), 0);
-
- // Set up concurrent alerts (that started recently).
- int id6 = at.addAlertRow(6, SCHEDULED, ACCEPTED, 0, createTimeInMillis(5, 0),
- createTimeInMillis(5, 40), 0);
- int id5 = at.addAlertRow(5, SCHEDULED, ACCEPTED, 0, createTimeInMillis(4, 55),
- createTimeInMillis(7, 30), 0);
- int id4 = at.addAlertRow(4, SCHEDULED, ACCEPTED, 0, createTimeInMillis(4, 50),
- createTimeInMillis(4, 50), 0);
-
- // Set up past alerts.
- int id3 = at.addAlertRow(3, SCHEDULED, ACCEPTED, 0, createTimeInMillis(3, 0),
- createTimeInMillis(4, 0), 0);
- int id2 = at.addAlertRow(2, SCHEDULED, ACCEPTED, 0, createTimeInMillis(2, 0),
- createTimeInMillis(3, 0), 0);
- int id1 = at.addAlertRow(1, SCHEDULED, ACCEPTED, 0, createTimeInMillis(1, 0),
- createTimeInMillis(2, 0), 0);
-
- // Check posted notifications. The order listed here is the order simulates the
- // order in the real notification bar (last one posted appears on top), so these
- // should be lowest start time on top.
- ntm.expectTestNotification(6, id4, PRIORITY_HIGH); // concurrent
- ntm.expectTestNotification(5, id5, PRIORITY_HIGH); // concurrent
- ntm.expectTestNotification(4, id6, PRIORITY_HIGH); // concurrent
- ntm.expectTestNotification(3, id7, PRIORITY_HIGH); // future
- ntm.expectTestNotification(2, id8, PRIORITY_HIGH); // future
- ntm.expectTestNotification(1, id9, PRIORITY_HIGH); // future
- ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID,
- new int[] {id3, id2, id1}, PRIORITY_MIN);
- AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
- currentTime, maxNotifications);
- ntm.validateNotificationsAndReset();
-
- // Increase time by 15 minutes to check that some concurrent events dropped
- // to the low priority bucket.
- currentTime = createTimeInMillis(5, 15);
- ntm.expectTestNotification(4, id5, PRIORITY_HIGH); // concurrent
- ntm.expectTestNotification(3, id7, PRIORITY_HIGH); // future
- ntm.expectTestNotification(2, id8, PRIORITY_HIGH); // future
- ntm.expectTestNotification(1, id9, PRIORITY_HIGH); // future
- ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID,
- new int[] {id6, id4, id3, id2, id1}, PRIORITY_MIN);
- AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
- currentTime, maxNotifications);
- ntm.validateNotificationsAndReset();
-
- // Increase time so some of the previously future ones change state.
- currentTime = createTimeInMillis(8, 15);
- ntm.expectTestNotification(1, id9, PRIORITY_HIGH); // future
- ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID,
- new int[] {id8, id7, id6, id5, id4, id3, id2, id1}, PRIORITY_MIN);
- AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
- currentTime, maxNotifications);
- ntm.validateNotificationsAndReset();
- }
-
- @SmallTest
- public void testGenerateAlerts_maxAlerts() {
- MockSharedPreferences prefs = new MockSharedPreferences();
- MockAlarmManager alarmMgr = new MockAlarmManager(mContext);
- AlertsTable at = new AlertsTable();
-
- // Current time - 5:00
- long currentTime = createTimeInMillis(5, 0);
-
- // Set up future alerts. The real query implementation sorts by descending start
- // time so simulate that here with our order of adds to AlertsTable.
- int id9 = at.addAlertRow(9, SCHEDULED, ACCEPTED, 0, createTimeInMillis(9, 0),
- createTimeInMillis(10, 0), 0);
- int id8 = at.addAlertRow(8, SCHEDULED, ACCEPTED, 0, createTimeInMillis(8, 0),
- createTimeInMillis(9, 0), 0);
- int id7 = at.addAlertRow(7, SCHEDULED, ACCEPTED, 0, createTimeInMillis(7, 0),
- createTimeInMillis(8, 0), 0);
-
- // Set up concurrent alerts (that started recently).
- int id6 = at.addAlertRow(6, SCHEDULED, ACCEPTED, 0, createTimeInMillis(5, 0),
- createTimeInMillis(5, 40), 0);
- int id5 = at.addAlertRow(5, SCHEDULED, ACCEPTED, 0, createTimeInMillis(4, 55),
- createTimeInMillis(7, 30), 0);
- int id4 = at.addAlertRow(4, SCHEDULED, ACCEPTED, 0, createTimeInMillis(4, 50),
- createTimeInMillis(4, 50), 0);
-
- // Set up past alerts.
- int id3 = at.addAlertRow(3, SCHEDULED, ACCEPTED, 0, createTimeInMillis(3, 0),
- createTimeInMillis(4, 0), 0);
- int id2 = at.addAlertRow(2, SCHEDULED, ACCEPTED, 0, createTimeInMillis(2, 0),
- createTimeInMillis(3, 0), 0);
- int id1 = at.addAlertRow(1, SCHEDULED, ACCEPTED, 0, createTimeInMillis(1, 0),
- createTimeInMillis(2, 0), 0);
-
- // Test when # alerts = max.
- int maxNotifications = 6;
- NotificationTestManager ntm = new NotificationTestManager(at.mAlerts, maxNotifications);
- ntm.expectTestNotification(6, id4, PRIORITY_HIGH); // concurrent
- ntm.expectTestNotification(5, id5, PRIORITY_HIGH); // concurrent
- ntm.expectTestNotification(4, id6, PRIORITY_HIGH); // concurrent
- ntm.expectTestNotification(3, id7, PRIORITY_HIGH); // future
- ntm.expectTestNotification(2, id8, PRIORITY_HIGH); // future
- ntm.expectTestNotification(1, id9, PRIORITY_HIGH); // future
- ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID,
- new int[] {id3, id2, id1}, PRIORITY_MIN);
- AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
- currentTime, maxNotifications);
- ntm.validateNotificationsAndReset();
-
- // Test when # alerts > max.
- maxNotifications = 4;
- ntm = new NotificationTestManager(at.mAlerts, maxNotifications);
- ntm.expectTestNotification(4, id4, PRIORITY_HIGH); // concurrent
- ntm.expectTestNotification(3, id5, PRIORITY_HIGH); // concurrent
- ntm.expectTestNotification(2, id6, PRIORITY_HIGH); // concurrent
- ntm.expectTestNotification(1, id7, PRIORITY_HIGH); // future
- ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID,
- new int[] {id9, id8, id3, id2, id1}, PRIORITY_MIN);
- AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
- currentTime, maxNotifications);
- ntm.validateNotificationsAndReset();
- }
-
- /**
- * Test that the SharedPreferences are only fetched once for each setting.
- */
- @SmallTest
- public void testGenerateAlerts_sharedPreferences() {
- MockSharedPreferences prefs = new MockSharedPreferences(true /* strict mode */);
- AlertsTable at = new AlertsTable();
- NotificationTestManager ntm = new NotificationTestManager(at.mAlerts,
- AlertService.MAX_NOTIFICATIONS);
-
- // Current time - 5:00
- long currentTime = createTimeInMillis(5, 0);
-
- // Set up future alerts. The real query implementation sorts by descending start
- // time so simulate that here with our order of adds to AlertsTable.
- at.addAlertRow(3, SCHEDULED, ACCEPTED, 0, createTimeInMillis(9, 0),
- createTimeInMillis(10, 0), 0);
- at.addAlertRow(2, SCHEDULED, ACCEPTED, 0, createTimeInMillis(8, 0),
- createTimeInMillis(9, 0), 0);
- at.addAlertRow(1, SCHEDULED, ACCEPTED, 0, createTimeInMillis(7, 0),
- createTimeInMillis(8, 0), 0);
-
- // If this does not result in a failure (MockSharedPreferences fails for duplicate
- // queries), then test passes.
- AlertService.generateAlerts(mContext, ntm, new MockAlarmManager(mContext), prefs,
- at.getAlertCursor(), currentTime, AlertService.MAX_NOTIFICATIONS);
- }
-
- public void testGenerateAlerts_refreshTime() {
- AlertsTable at = new AlertsTable();
- MockSharedPreferences prefs = new MockSharedPreferences();
- MockAlarmManager alarmMgr = new MockAlarmManager(mContext);
- NotificationTestManager ntm = new NotificationTestManager(at.mAlerts,
- AlertService.MAX_NOTIFICATIONS);
-
- // Since AlertService.processQuery uses DateUtils.isToday instead of checking against
- // the passed in currentTime (not worth allocating the extra Time objects to do so), use
- // today's date for this test.
- Time now = new Time();
- now.setToNow();
- int day = now.monthDay;
- int month = now.month;
- int year = now.year;
- Time yesterday = new Time();
- yesterday.set(System.currentTimeMillis() - DateUtils.DAY_IN_MILLIS);
- Time tomorrow = new Time();
- tomorrow.set(System.currentTimeMillis() + DateUtils.DAY_IN_MILLIS);
- long allDayStart = Utils.createTimeInMillis(0, 0, 0, day, month, year, Time.TIMEZONE_UTC);
-
- /* today 10am - 10:30am */
- int id4 = at.addAlertRow(4, SCHEDULED, ACCEPTED, 0,
- Utils.createTimeInMillis(0, 0, 10, day, month, year, Time.getCurrentTimezone()),
- Utils.createTimeInMillis(0, 30, 10, day, month, year, Time.getCurrentTimezone()),
- 0);
- /* today 6am - 6am (0 duration event) */
- int id3 = at.addAlertRow(3, SCHEDULED, ACCEPTED, 0,
- Utils.createTimeInMillis(0, 0, 6, day, month, year, Time.getCurrentTimezone()),
- Utils.createTimeInMillis(0, 0, 6, day, month, year, Time.getCurrentTimezone()), 0);
- /* today allDay */
- int id2 = at.addAlertRow(2, SCHEDULED, ACCEPTED, 1, allDayStart,
- allDayStart + DateUtils.HOUR_IN_MILLIS * 24, 0);
- /* yesterday 11pm - today 7am (multiday event) */
- int id1 = at.addAlertRow(1, SCHEDULED, ACCEPTED, 0,
- Utils.createTimeInMillis(0, 0, 23, yesterday.monthDay, yesterday.month,
- yesterday.year, Time.getCurrentTimezone()),
- Utils.createTimeInMillis(0, 0, 7, day, month, year, Time.getCurrentTimezone()), 0);
-
- // Test at midnight - next refresh should be 15 min later (15 min into the all
- // day event).
- long currentTime = Utils.createTimeInMillis(0, 0, 0, day, month, year,
- Time.getCurrentTimezone());
- alarmMgr.expectAlarmTime(AlarmManager.RTC, currentTime + 15 * DateUtils.MINUTE_IN_MILLIS);
- ntm.expectTestNotification(4, id1, PRIORITY_HIGH);
- ntm.expectTestNotification(3, id2, PRIORITY_HIGH);
- ntm.expectTestNotification(2, id3, PRIORITY_HIGH);
- ntm.expectTestNotification(1, id4, PRIORITY_HIGH);
- AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
- currentTime, AlertService.MAX_NOTIFICATIONS);
- ntm.validateNotificationsAndReset();
-
- // Test at 12:30am - next refresh should be 30 min later (1/4 into event 'id1').
- currentTime = Utils.createTimeInMillis(0, 30, 0, day, month, year,
- Time.getCurrentTimezone());
- alarmMgr.expectAlarmTime(AlarmManager.RTC, currentTime + 30 * DateUtils.MINUTE_IN_MILLIS);
- ntm.expectTestNotification(3, id1, PRIORITY_HIGH);
- ntm.expectTestNotification(2, id3, PRIORITY_HIGH);
- ntm.expectTestNotification(1, id4, PRIORITY_HIGH);
- ntm.expectTestNotification(4, id2, PRIORITY_DEFAULT);
- AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
- currentTime, AlertService.MAX_NOTIFICATIONS);
- ntm.validateNotificationsAndReset();
-
- // Test at 5:55am - next refresh should be 20 min later (15 min after 'id3').
- currentTime = Utils.createTimeInMillis(0, 55, 5, day, month, year,
- Time.getCurrentTimezone());
- alarmMgr.expectAlarmTime(AlarmManager.RTC, currentTime + 20 * DateUtils.MINUTE_IN_MILLIS);
- ntm.expectTestNotification(2, id3, PRIORITY_HIGH);
- ntm.expectTestNotification(1, id4, PRIORITY_HIGH);
- ntm.expectTestNotification(3, id2, PRIORITY_DEFAULT);
- ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID, id1, PRIORITY_MIN);
- AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
- currentTime, AlertService.MAX_NOTIFICATIONS);
- ntm.validateNotificationsAndReset();
-
- // Test at 10:14am - next refresh should be 1 min later (15 min into event 'id4').
- currentTime = Utils.createTimeInMillis(0, 14, 10, day, month, year,
- Time.getCurrentTimezone());
- alarmMgr.expectAlarmTime(AlarmManager.RTC, currentTime + 1 * DateUtils.MINUTE_IN_MILLIS);
- ntm.expectTestNotification(1, id4, PRIORITY_HIGH);
- ntm.expectTestNotification(2, id2, PRIORITY_DEFAULT);
- ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID, new int[] {id3, id1},
- PRIORITY_MIN);
- AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
- currentTime, AlertService.MAX_NOTIFICATIONS);
- ntm.validateNotificationsAndReset();
-
- // Test at 10:15am - next refresh should be tomorrow midnight (end of all day event 'id2').
- currentTime = Utils.createTimeInMillis(0, 15, 10, day, month, year,
- Time.getCurrentTimezone());
- alarmMgr.expectAlarmTime(AlarmManager.RTC, Utils.createTimeInMillis(0, 0, 23,
- tomorrow.monthDay, tomorrow.month, tomorrow.year, Time.getCurrentTimezone()));
- ntm.expectTestNotification(1, id2, PRIORITY_DEFAULT);
- ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID,
- new int[] {id4, id3, id1}, PRIORITY_MIN);
- AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
- currentTime, AlertService.MAX_NOTIFICATIONS);
- ntm.validateNotificationsAndReset();
- }
-
- private NotificationInfo createNotificationInfo(long eventId) {
- return new NotificationInfo("eventName", "location", "description", 100L, 200L, eventId,
- false, false);
- }
-
- private static long createTimeInMillis(int hour, int minute) {
- return Utils.createTimeInMillis(0 /* second */, minute, hour, 1 /* day */, 1 /* month */,
- 2012 /* year */, Time.getCurrentTimezone());
- }
-
- @SmallTest
- public void testProcessQuery_skipDeclinedDismissed() {
- int declinedEventId = 1;
- int dismissedEventId = 2;
- int acceptedEventId = 3;
- long acceptedStartTime = createTimeInMillis(10, 0);
- long acceptedEndTime = createTimeInMillis(10, 30);
-
- AlertsTable at = new AlertsTable();
- at.addAlertRow(declinedEventId, SCHEDULED, DECLINED, 0, createTimeInMillis(9, 0),
- createTimeInMillis(10, 0), 0);
- at.addAlertRow(dismissedEventId, SCHEDULED, DISMISSED, 0, createTimeInMillis(9, 30),
- createTimeInMillis(11, 0), 0);
- at.addAlertRow(acceptedEventId, SCHEDULED, ACCEPTED, 1, acceptedStartTime, acceptedEndTime,
- 0);
-
- ArrayList<NotificationInfo> highPriority = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> mediumPriority = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> lowPriority = new ArrayList<NotificationInfo>();
- long currentTime = createTimeInMillis(5, 0);
- AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
- mediumPriority, lowPriority);
-
- assertEquals(0, lowPriority.size());
- assertEquals(0, mediumPriority.size());
- assertEquals(1, highPriority.size());
- assertEquals(acceptedEventId, highPriority.get(0).eventId);
- assertEquals(acceptedStartTime, highPriority.get(0).startMillis);
- assertEquals(acceptedEndTime, highPriority.get(0).endMillis);
- assertTrue(highPriority.get(0).allDay);
- }
-
- @SmallTest
- public void testProcessQuery_newAlert() {
- int scheduledAlertEventId = 1;
- int firedAlertEventId = 2;
-
- AlertsTable at = new AlertsTable();
- at.addAlertRow(scheduledAlertEventId, SCHEDULED, ACCEPTED, 0, createTimeInMillis(9, 0),
- createTimeInMillis(10, 0), 0);
- at.addAlertRow(firedAlertEventId, FIRED, ACCEPTED, 0, createTimeInMillis(4, 0),
- createTimeInMillis(10, 30), 0);
-
- ArrayList<NotificationInfo> highPriority = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> mediumPriority = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> lowPriority = new ArrayList<NotificationInfo>();
- long currentTime = createTimeInMillis(5, 0);
- AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
- mediumPriority, lowPriority);
-
- assertEquals(0, lowPriority.size());
- assertEquals(0, mediumPriority.size());
- assertEquals(2, highPriority.size());
- assertEquals(scheduledAlertEventId, highPriority.get(0).eventId);
- assertTrue("newAlert should be ON for scheduled alerts", highPriority.get(0).newAlert);
- assertEquals(firedAlertEventId, highPriority.get(1).eventId);
- assertFalse("newAlert should be OFF for fired alerts", highPriority.get(1).newAlert);
- }
-
- @SmallTest
- public void testProcessQuery_recurringEvent() {
- int eventId = 1;
- long earlierStartTime = createTimeInMillis(10, 0);
- long laterStartTime = createTimeInMillis(11, 0);
-
- ArrayList<NotificationInfo> highPriority = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> mediumPriority = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> lowPriority = new ArrayList<NotificationInfo>();
-
- AlertsTable at = new AlertsTable();
- at.addAlertRow(eventId, SCHEDULED, ACCEPTED, 0, laterStartTime,
- laterStartTime + DateUtils.HOUR_IN_MILLIS, 0);
- at.addAlertRow(eventId, FIRED, ACCEPTED, 0, earlierStartTime,
- earlierStartTime + DateUtils.HOUR_IN_MILLIS, 0);
-
- // Both events in the future: the earliest one should be chosen.
- long currentTime = earlierStartTime - DateUtils.DAY_IN_MILLIS * 5;
- AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
- mediumPriority, lowPriority);
- assertEquals(0, lowPriority.size());
- assertEquals(0, mediumPriority.size());
- assertEquals(1, highPriority.size());
- assertEquals("Recurring event with earlier start time expected", earlierStartTime,
- highPriority.get(0).startMillis);
-
- // Increment time just past the earlier event: the earlier one should be chosen.
- highPriority.clear();
- currentTime = earlierStartTime + DateUtils.MINUTE_IN_MILLIS * 10;
- AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
- mediumPriority, lowPriority);
- assertEquals(0, lowPriority.size());
- assertEquals(0, mediumPriority.size());
- assertEquals(1, highPriority.size());
- assertEquals("Recurring event with earlier start time expected", earlierStartTime,
- highPriority.get(0).startMillis);
-
- // Increment time to 15 min past the earlier event: the later one should be chosen.
- highPriority.clear();
- currentTime = earlierStartTime + DateUtils.MINUTE_IN_MILLIS * 15;
- AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
- mediumPriority, lowPriority);
- assertEquals(0, lowPriority.size());
- assertEquals(0, mediumPriority.size());
- assertEquals(1, highPriority.size());
- assertEquals("Recurring event with later start time expected", laterStartTime,
- highPriority.get(0).startMillis);
-
- // Both events in the past: the later one should be chosen (in the low priority bucket).
- highPriority.clear();
- currentTime = laterStartTime + DateUtils.DAY_IN_MILLIS * 5;
- AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
- mediumPriority, lowPriority);
- assertEquals(0, highPriority.size());
- assertEquals(0, mediumPriority.size());
- assertEquals(1, lowPriority.size());
- assertEquals("Recurring event with later start time expected", laterStartTime,
- lowPriority.get(0).startMillis);
- }
-
- @SmallTest
- public void testProcessQuery_recurringAllDayEvent() {
- int eventId = 1;
- long day1 = Utils.createTimeInMillis(0, 0, 0, 1, 5, 2012, Time.TIMEZONE_UTC);
- long day2 = Utils.createTimeInMillis(0, 0, 0, 2, 5, 2012, Time.TIMEZONE_UTC);
-
- ArrayList<NotificationInfo> highPriority = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> mediumPriority = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> lowPriority = new ArrayList<NotificationInfo>();
-
- AlertsTable at = new AlertsTable();
- at.addAlertRow(eventId, SCHEDULED, ACCEPTED, 1, day2, day2 + DateUtils.HOUR_IN_MILLIS * 24,
- 0);
- at.addAlertRow(eventId, SCHEDULED, ACCEPTED, 1, day1, day1 + DateUtils.HOUR_IN_MILLIS * 24,
- 0);
-
- // Both events in the future: the earliest one should be chosen.
- long currentTime = day1 - DateUtils.DAY_IN_MILLIS * 3;
- AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
- mediumPriority, lowPriority);
- assertEquals(0, lowPriority.size());
- assertEquals(0, mediumPriority.size());
- assertEquals(1, highPriority.size());
- assertEquals("Recurring event with earlier start time expected", day1,
- highPriority.get(0).startMillis);
-
- // Increment time just past the earlier event (to 12:10am). The earlier one should
- // be chosen.
- highPriority.clear();
- currentTime = Utils.createTimeInMillis(0, 10, 0, 1, 5, 2012, Time.getCurrentTimezone());
- AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
- mediumPriority, lowPriority);
- assertEquals(0, lowPriority.size());
- assertEquals(0, mediumPriority.size());
- assertEquals(1, highPriority.size());
- assertEquals("Recurring event with earlier start time expected", day1,
- highPriority.get(0).startMillis);
-
- // Increment time to 15 min past the earlier event: the later one should be chosen.
- highPriority.clear();
- currentTime = Utils.createTimeInMillis(0, 15, 0, 1, 5, 2012, Time.getCurrentTimezone());
- AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
- mediumPriority, lowPriority);
- assertEquals(0, lowPriority.size());
- assertEquals(0, mediumPriority.size());
- assertEquals(1, highPriority.size());
- assertEquals("Recurring event with earlier start time expected", day2,
- highPriority.get(0).startMillis);
-
- // Both events in the past: the later one should be chosen (in the low priority bucket).
- highPriority.clear();
- currentTime = day2 + DateUtils.DAY_IN_MILLIS * 1;
- AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
- mediumPriority, lowPriority);
- assertEquals(0, highPriority.size());
- assertEquals(0, mediumPriority.size());
- assertEquals(1, lowPriority.size());
- assertEquals("Recurring event with later start time expected", day2,
- lowPriority.get(0).startMillis);
- }
-
- @SmallTest
- public void testRedistributeBuckets_withinLimits() throws Exception {
- int maxNotifications = 3;
- ArrayList<NotificationInfo> threeItemList = new ArrayList<NotificationInfo>();
- threeItemList.add(createNotificationInfo(5));
- threeItemList.add(createNotificationInfo(4));
- threeItemList.add(createNotificationInfo(3));
-
- // Test when max notifications at high priority.
- ArrayList<NotificationInfo> high = threeItemList;
- ArrayList<NotificationInfo> medium = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> low = new ArrayList<NotificationInfo>();
- AlertService.redistributeBuckets(high, medium, low, maxNotifications);
- assertEquals(3, high.size());
- assertEquals(0, medium.size());
- assertEquals(0, low.size());
-
- // Test when max notifications at medium priority.
- high = new ArrayList<NotificationInfo>();
- medium = threeItemList;
- low = new ArrayList<NotificationInfo>();
- AlertService.redistributeBuckets(high, medium, low, maxNotifications);
- assertEquals(0, high.size());
- assertEquals(3, medium.size());
- assertEquals(0, low.size());
-
- // Test when max notifications at high and medium priority
- high = new ArrayList<NotificationInfo>(threeItemList);
- medium = new ArrayList<NotificationInfo>();
- medium.add(high.remove(1));
- low = new ArrayList<NotificationInfo>();
- AlertService.redistributeBuckets(high, medium, low, maxNotifications);
- assertEquals(2, high.size());
- assertEquals(1, medium.size());
- assertEquals(0, low.size());
- }
-
- @SmallTest
- public void testRedistributeBuckets_tooManyHighPriority() throws Exception {
- ArrayList<NotificationInfo> high = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> medium = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> low = new ArrayList<NotificationInfo>();
- high.add(createNotificationInfo(5));
- high.add(createNotificationInfo(4));
- high.add(createNotificationInfo(3));
- high.add(createNotificationInfo(2));
- high.add(createNotificationInfo(1));
-
- // Invoke the method under test.
- int maxNotifications = 3;
- AlertService.redistributeBuckets(high, medium, low, maxNotifications);
-
- // Verify some high priority were kicked out.
- assertEquals(3, high.size());
- assertEquals(3, high.get(0).eventId);
- assertEquals(2, high.get(1).eventId);
- assertEquals(1, high.get(2).eventId);
-
- // Verify medium priority untouched.
- assertEquals(0, medium.size());
-
- // Verify the extras went to low priority.
- assertEquals(2, low.size());
- assertEquals(5, low.get(0).eventId);
- assertEquals(4, low.get(1).eventId);
- }
-
- @SmallTest
- public void testRedistributeBuckets_tooManyMediumPriority() throws Exception {
- ArrayList<NotificationInfo> high = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> medium = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> low = new ArrayList<NotificationInfo>();
- high.add(createNotificationInfo(5));
- high.add(createNotificationInfo(4));
- medium.add(createNotificationInfo(3));
- medium.add(createNotificationInfo(2));
- medium.add(createNotificationInfo(1));
-
- // Invoke the method under test.
- int maxNotifications = 3;
- AlertService.redistributeBuckets(high, medium, low, maxNotifications);
-
- // Verify high priority untouched.
- assertEquals(2, high.size());
- assertEquals(5, high.get(0).eventId);
- assertEquals(4, high.get(1).eventId);
-
- // Verify some medium priority were kicked out (the ones near the end of the
- // list).
- assertEquals(1, medium.size());
- assertEquals(3, medium.get(0).eventId);
-
- // Verify the extras went to low priority.
- assertEquals(2, low.size());
- assertEquals(2, low.get(0).eventId);
- assertEquals(1, low.get(1).eventId);
- }
-
- @SmallTest
- public void testRedistributeBuckets_tooManyHighMediumPriority() throws Exception {
- ArrayList<NotificationInfo> high = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> medium = new ArrayList<NotificationInfo>();
- ArrayList<NotificationInfo> low = new ArrayList<NotificationInfo>();
- high.add(createNotificationInfo(8));
- high.add(createNotificationInfo(7));
- high.add(createNotificationInfo(6));
- high.add(createNotificationInfo(5));
- high.add(createNotificationInfo(4));
- medium.add(createNotificationInfo(3));
- medium.add(createNotificationInfo(2));
- medium.add(createNotificationInfo(1));
-
- // Invoke the method under test.
- int maxNotifications = 3;
- AlertService.redistributeBuckets(high, medium, low, maxNotifications);
-
- // Verify high priority.
- assertEquals(3, high.size());
- assertEquals(6, high.get(0).eventId);
- assertEquals(5, high.get(1).eventId);
- assertEquals(4, high.get(2).eventId);
-
- // Verify some medium priority.
- assertEquals(0, medium.size());
-
- // Verify low priority.
- assertEquals(5, low.size());
- assertEquals(8, low.get(0).eventId);
- assertEquals(7, low.get(1).eventId);
- assertEquals(3, low.get(2).eventId);
- assertEquals(2, low.get(3).eventId);
- assertEquals(1, low.get(4).eventId);
- }
-}
diff --git a/tests/src/com/android/calendar/alerts/MockAlarmManager.java b/tests/src/com/android/calendar/alerts/MockAlarmManager.java
deleted file mode 100644
index 067a7865..00000000
--- a/tests/src/com/android/calendar/alerts/MockAlarmManager.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2012 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.alerts;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.text.format.DateUtils;
-
-import junit.framework.Assert;
-
-public class MockAlarmManager implements AlarmManagerInterface {
- private Context context;
- private int expectedAlarmType = -1;
- private long expectedAlarmTime = -1;
- private boolean alarmSet = false;
-
- MockAlarmManager(Context context) {
- this.context = context;
- }
-
- public void expectAlarmTime(int type, long millis) {
- this.expectedAlarmType = type;
- this.expectedAlarmTime = millis;
- }
-
- @Override
- public void set(int actualAlarmType, long actualAlarmTime, PendingIntent operation) {
- Assert.assertNotNull(operation);
- alarmSet = true;
- if (expectedAlarmType != -1) {
- Assert.assertEquals("Alarm type not expected.", expectedAlarmType, actualAlarmType);
- Assert.assertEquals("Alarm time not expected. Expected:" + DateUtils.formatDateTime(
- context, expectedAlarmTime, DateUtils.FORMAT_SHOW_TIME) + ", actual:"
- + DateUtils.formatDateTime(context, actualAlarmTime,
- DateUtils.FORMAT_SHOW_TIME), expectedAlarmTime, actualAlarmTime);
- }
- }
-
- /**
- * Returns whether set() was invoked.
- */
- public boolean isAlarmSet() {
- return alarmSet;
- }
-}
diff --git a/tests/src/com/android/calendar/alerts/Utils.java b/tests/src/com/android/calendar/alerts/Utils.java
deleted file mode 100644
index b887c4b9..00000000
--- a/tests/src/com/android/calendar/alerts/Utils.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2012 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.alerts;
-
-import android.text.format.Time;
-
-class Utils {
- public static long createTimeInMillis(int second, int minute, int hour, int monthDay,
- int month, int year, String timezone) {
- Time t = new Time(timezone);
- t.set(second, minute, hour, monthDay, month, year);
- t.normalize(false);
- return t.toMillis(false);
- }
-}
diff --git a/tests/src/com/android/calendar/event/EditEventHelperTest.java b/tests/src/com/android/calendar/event/EditEventHelperTest.java
deleted file mode 100644
index 46941fe2..00000000
--- a/tests/src/com/android/calendar/event/EditEventHelperTest.java
+++ /dev/null
@@ -1,1645 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.calendar.event;
-
-import android.content.ContentProvider;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentValues;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.net.Uri;
-import android.provider.CalendarContract.Attendees;
-import android.provider.CalendarContract.Events;
-import android.provider.CalendarContract.Reminders;
-import android.test.AndroidTestCase;
-import android.test.mock.MockResources;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Smoke;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-import android.text.util.Rfc822Token;
-
-import com.android.calendar.AbstractCalendarActivity;
-import com.android.calendar.AsyncQueryService;
-import com.android.calendar.CalendarEventModel;
-import com.android.calendar.CalendarEventModel.ReminderEntry;
-import com.android.calendar.R;
-import com.android.calendar.Utils;
-import com.android.common.Rfc822Validator;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.LinkedHashSet;
-import java.util.TimeZone;
-
-public class EditEventHelperTest extends AndroidTestCase {
- private static final int TEST_EVENT_ID = 1;
- private static final int TEST_EVENT_INDEX_ID = 0;
- private static final long TEST_END = 1272931200000L;
- private static long TEST_END2 = 1272956400000L;
- private static final long TEST_START = 1272844800000L;
- private static long TEST_START2 = 1272870000000L;
- private static final String LOCAL_TZ = TimeZone.getDefault().getID();
-
- private static final int SAVE_EVENT_NEW_EVENT = 1;
- private static final int SAVE_EVENT_MOD_RECUR = 2;
- private static final int SAVE_EVENT_RECUR_TO_NORECUR = 3;
- private static final int SAVE_EVENT_NORECUR_TO_RECUR= 4;
- private static final int SAVE_EVENT_MOD_NORECUR = 5;
- private static final int SAVE_EVENT_MOD_INSTANCE = 6;
- private static final int SAVE_EVENT_ALLFOLLOW_TO_NORECUR = 7;
- private static final int SAVE_EVENT_FIRST_TO_NORECUR = 8;
- private static final int SAVE_EVENT_FIRST_TO_RECUR = 9;
- private static final int SAVE_EVENT_ALLFOLLOW_TO_RECUR = 10;
-
- /* These should match up with EditEventHelper.EVENT_PROJECTION.
- * Note that spaces and commas have been removed to allow for easier sanitation.
- */
- private static String[] TEST_CURSOR_DATA = new String[] {
- Integer.toString(TEST_EVENT_ID), // 0 _id
- "The_Question", // 1 title
- "Evaluating_Life_the_Universe_and_Everything", // 2 description
- "Earth_Mk2", // 3 location
- "1", // 4 All Day
- "0", // 5 Has alarm
- "2", // 6 Calendar id
- "1272844800000", // 7 dtstart, Monday, May 3rd midnight UTC
- "1272931200000", // 8 dtend, Tuesday, May 4th midnight UTC
- "P3652421990D", // 9 duration, (10 million years)
- "UTC", // 10 event timezone
- "FREQ=DAILY;WKST=SU", // 11 rrule
- "unique_per_calendar_stuff", // 12 sync id
- "0", // 13 transparency/availability
- "3", // 14 visibility/access level
- "steve@gmail.com", // 15 owner account
- "1", // 16 has attendee data
- null, //17 originalSyncId
- "organizer@gmail.com", // 18 organizer
- "0", // 19 guest can modify
- "-1", // 20 original id
- "1", // 21 event status
- "-339611", // 22 calendar color
- "-2350809", // 23 event color
- "11" // 24 event color key
- };
-
- private static final String AUTHORITY_URI = "content://EditEventHelperAuthority/";
- private static final String AUTHORITY = "EditEventHelperAuthority";
-
- private static final String TEST_ADDRESSES =
- "no good, ad1@email.com, \"First Last\" <first@email.com> (comment), " +
- "one.two.three@email.grue";
- private static final String TEST_ADDRESSES2 =
- "no good, ad1@email.com, \"First Last\" <first@email.com> (comment), " +
- "different@email.bit";
- private static final String TEST_ADDRESSES3 =
- "ad1@email.com, \"First Last\" <first@email.com> (comment), " +
- "different@email.bit";
- private static final String TEST_ADDRESSES4 =
- "ad1@email.com, \"First Last\" <first@email.com> (comment), " +
- "one.two.three@email.grue";
-
-
- private static final String TAG = "EEHTest";
-
- private Rfc822Validator mEmailValidator;
- private CalendarEventModel mModel1;
- private CalendarEventModel mModel2;
-
- private ContentValues mValues;
- private ContentValues mExpectedValues;
-
- private EditEventHelper mHelper;
- private AbstractCalendarActivity mActivity;
- private int mCurrentSaveTest = 0;
-
- @Override
- public void setUp() {
- Time time = new Time(Time.TIMEZONE_UTC);
- time.set(TEST_START);
- time.timezone = LOCAL_TZ;
- TEST_START2 = time.normalize(true);
-
- time.timezone = Time.TIMEZONE_UTC;
- time.set(TEST_END);
- time.timezone = LOCAL_TZ;
- TEST_END2 = time.normalize(true);
-
- mEmailValidator = new Rfc822Validator(null);
- }
-
- private class MockAbsCalendarActivity extends AbstractCalendarActivity {
- @Override
- public AsyncQueryService getAsyncQueryService() {
- if (mService == null) {
- mService = new AsyncQueryService(this) {
- @Override
- public void startBatch(int token, Object cookie, String authority,
- ArrayList<ContentProviderOperation> cpo, long delayMillis) {
- mockApplyBatch(authority, cpo);
- }
- };
- }
- return mService;
- }
-
- @Override
- public Resources getResources() {
- Resources res = new MockResources() {
- @Override
- // The actual selects singular vs plural as well and in the given language
- public String getQuantityString(int id, int quantity) {
- if (id == R.plurals.Nmins) {
- return quantity + " mins";
- }
- if (id == R.plurals.Nminutes) {
- return quantity + " minutes";
- }
- if (id == R.plurals.Nhours) {
- return quantity + " hours";
- }
- if (id == R.plurals.Ndays) {
- return quantity + " days";
- }
- return id + " " + quantity;
- }
- };
- return res;
- }
- }
-
- private AbstractCalendarActivity buildTestContext() {
- MockAbsCalendarActivity context = new MockAbsCalendarActivity();
- return context;
- }
-
- private ContentProviderResult[] mockApplyBatch(String authority,
- ArrayList<ContentProviderOperation> operations) {
- switch (mCurrentSaveTest) {
- case SAVE_EVENT_NEW_EVENT:
- // new recurring event
- verifySaveEventNewEvent(operations);
- break;
- case SAVE_EVENT_MOD_RECUR:
- // update to recurring event
- verifySaveEventModifyRecurring(operations);
- break;
- case SAVE_EVENT_RECUR_TO_NORECUR:
- // replace recurring event with non-recurring event
- verifySaveEventRecurringToNonRecurring(operations);
- break;
- case SAVE_EVENT_NORECUR_TO_RECUR:
- // update non-recurring event with recurring event
- verifySaveEventNonRecurringToRecurring(operations);
- break;
- case SAVE_EVENT_MOD_NORECUR:
- // update to non-recurring
- verifySaveEventUpdateNonRecurring(operations);
- break;
- case SAVE_EVENT_MOD_INSTANCE:
- // update to single instance of recurring event
- verifySaveEventModifySingleInstance(operations);
- break;
- case SAVE_EVENT_ALLFOLLOW_TO_NORECUR:
- // update all following with non-recurring event
- verifySaveEventModifyAllFollowingWithNonRecurring(operations);
- break;
- case SAVE_EVENT_FIRST_TO_NORECUR:
- // update all following with non-recurring event on first event in series
- verifySaveEventModifyAllFollowingFirstWithNonRecurring(operations);
- break;
- case SAVE_EVENT_FIRST_TO_RECUR:
- // update all following with recurring event on first event in series
- verifySaveEventModifyAllFollowingFirstWithRecurring(operations);
- break;
- case SAVE_EVENT_ALLFOLLOW_TO_RECUR:
- // update all following with recurring event on second event in series
- verifySaveEventModifyAllFollowingWithRecurring(operations);
- break;
- }
- return new ContentProviderResult[] {new ContentProviderResult(5)};
- }
-
- private void addOwnerAttendeeToOps(ArrayList<ContentProviderOperation> expectedOps, int id) {
- addOwnerAttendee();
- ContentProviderOperation.Builder b;
- b = ContentProviderOperation.newInsert(Attendees.CONTENT_URI).withValues(mExpectedValues);
- b.withValueBackReference(Reminders.EVENT_ID, id);
- expectedOps.add(b.build());
- }
-
- private void addOwnerAttendeeToOps(ArrayList<ContentProviderOperation> expectedOps) {
- addOwnerAttendee();
- mExpectedValues.put(Attendees.EVENT_ID, TEST_EVENT_ID);
- ContentProviderOperation.Builder b;
- b = ContentProviderOperation.newInsert(Attendees.CONTENT_URI).withValues(mExpectedValues);
- expectedOps.add(b.build());
- }
-
-
- // Some tests set the time values to one day later, this does that move in the values
- private void moveExpectedTimeValuesForwardOneDay() {
- long dayInMs = EditEventHelper.DAY_IN_SECONDS*1000;
- mExpectedValues.put(Events.DTSTART, TEST_START + dayInMs);
- mExpectedValues.put(Events.DTEND, TEST_END + dayInMs);
- }
-
- // Duplicates the delete and add for changing a single email address
- private void addAttendeeChangesOps(ArrayList<ContentProviderOperation> expectedOps) {
- ContentProviderOperation.Builder b =
- ContentProviderOperation.newDelete(Attendees.CONTENT_URI);
- b.withSelection(EditEventHelper.ATTENDEES_DELETE_PREFIX + "?)",
- new String[] {"one.two.three@email.grue"});
- expectedOps.add(b.build());
-
- mExpectedValues.clear();
- mExpectedValues.put(Attendees.ATTENDEE_NAME, "different@email.bit");
- mExpectedValues.put(Attendees.ATTENDEE_EMAIL, "different@email.bit");
- mExpectedValues.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
- mExpectedValues.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED);
- mExpectedValues.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_NONE);
- mExpectedValues.put(Attendees.EVENT_ID, TEST_EVENT_ID);
- b = ContentProviderOperation
- .newInsert(Attendees.CONTENT_URI)
- .withValues(mExpectedValues);
- expectedOps.add(b.build());
- }
-
- // This is a commonly added set of values
- private void addOwnerAttendee() {
- mExpectedValues.clear();
- mExpectedValues.put(Attendees.ATTENDEE_EMAIL, mModel1.mOwnerAccount);
- mExpectedValues.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ORGANIZER);
- mExpectedValues.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED);
- mExpectedValues.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_ACCEPTED);
- }
-
- /** Some tests add all the attendees to the db, the names and emails should match
- * with {@link #TEST_ADDRESSES2} minus the 'no good'
- */
- private void addTestAttendees(ArrayList<ContentProviderOperation> ops,
- boolean newEvent, int id) {
- ContentProviderOperation.Builder b;
- mExpectedValues.clear();
- mExpectedValues.put(Attendees.ATTENDEE_NAME, "ad1@email.com");
- mExpectedValues.put(Attendees.ATTENDEE_EMAIL, "ad1@email.com");
- mExpectedValues.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
- mExpectedValues.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED);
- mExpectedValues.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_NONE);
-
- if (newEvent) {
- b = ContentProviderOperation
- .newInsert(Attendees.CONTENT_URI)
- .withValues(mExpectedValues);
- b.withValueBackReference(Attendees.EVENT_ID, id);
- } else {
- mExpectedValues.put(Attendees.EVENT_ID, id);
- b = ContentProviderOperation
- .newInsert(Attendees.CONTENT_URI)
- .withValues(mExpectedValues);
- }
- ops.add(b.build());
-
- mExpectedValues.clear();
- mExpectedValues.put(Attendees.ATTENDEE_NAME, "First Last");
- mExpectedValues.put(Attendees.ATTENDEE_EMAIL, "first@email.com");
- mExpectedValues.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
- mExpectedValues.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED);
- mExpectedValues.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_NONE);
-
- if (newEvent) {
- b = ContentProviderOperation
- .newInsert(Attendees.CONTENT_URI)
- .withValues(mExpectedValues);
- b.withValueBackReference(Attendees.EVENT_ID, id);
- } else {
- mExpectedValues.put(Attendees.EVENT_ID, id);
- b = ContentProviderOperation
- .newInsert(Attendees.CONTENT_URI)
- .withValues(mExpectedValues);
- }
- ops.add(b.build());
-
- mExpectedValues.clear();
- mExpectedValues.put(Attendees.ATTENDEE_NAME, "different@email.bit");
- mExpectedValues.put(Attendees.ATTENDEE_EMAIL, "different@email.bit");
- mExpectedValues.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
- mExpectedValues.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED);
- mExpectedValues.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_NONE);
-
- if (newEvent) {
- b = ContentProviderOperation
- .newInsert(Attendees.CONTENT_URI)
- .withValues(mExpectedValues);
- b.withValueBackReference(Attendees.EVENT_ID, id);
- } else {
- mExpectedValues.put(Attendees.EVENT_ID, id);
- b = ContentProviderOperation
- .newInsert(Attendees.CONTENT_URI)
- .withValues(mExpectedValues);
- }
- ops.add(b.build());
- }
-
- @Smoke
- @SmallTest
- public void testSaveEventFailures() {
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- mModel1 = buildTestModel();
- mModel2 = buildTestModel();
-
- // saveEvent should return false early if:
- // -it was set to not ok
- // -the model was null
- // -the event doesn't represent the same event as the original event
- // -there's a uri but an original event is not provided
- mHelper.mEventOk = false;
- assertFalse(mHelper.saveEvent(null, null, 0));
- mHelper.mEventOk = true;
- assertFalse(mHelper.saveEvent(null, null, 0));
- mModel2.mId = 13;
- assertFalse(mHelper.saveEvent(mModel1, mModel2, 0));
- mModel2.mId = mModel1.mId;
- mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
- mModel2.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
- assertFalse(mHelper.saveEvent(mModel1, null, 0));
- }
-
- @Smoke
- @SmallTest
- public void testSaveEventNewEvent() {
- // Creates a model of a new event for saving
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- mModel1 = buildTestModel();
- mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
- mCurrentSaveTest = SAVE_EVENT_NEW_EVENT;
-
- assertTrue(mHelper.saveEvent(mModel1, null, 0));
- }
-
- private boolean verifySaveEventNewEvent(ArrayList<ContentProviderOperation> ops) {
- ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
- int br_id = 0;
- mExpectedValues = buildTestValues();
- mExpectedValues.put(Events.HAS_ALARM, 0);
- mExpectedValues.put(Events.HAS_ATTENDEE_DATA, 1);
- ContentProviderOperation.Builder b = ContentProviderOperation
- .newInsert(Events.CONTENT_URI)
- .withValues(mExpectedValues);
- expectedOps.add(b.build());
-
- // This call has a separate unit test so we'll use it to simplify making the expected vals
- mHelper.saveRemindersWithBackRef(expectedOps, br_id, mModel1.mReminders,
- new ArrayList<ReminderEntry>(), true);
-
- addOwnerAttendeeToOps(expectedOps, br_id);
-
- addTestAttendees(expectedOps, true, br_id);
-
- assertEquals(expectedOps, ops);
- return true;
- }
-
- @Smoke
- @SmallTest
- public void testSaveEventModifyRecurring() {
- // Creates an original and an updated recurring event model
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- mModel1 = buildTestModel();
- mModel2 = buildTestModel();
- mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
-
- // Updating a recurring event with a new attendee list
- mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
- // And a new start time to ensure the time fields aren't removed
- mModel1.mOriginalStart = TEST_START;
-
- // The original model is assumed correct so drop the no good bit
- mModel2.addAttendees(TEST_ADDRESSES4, null);
- mCurrentSaveTest = SAVE_EVENT_MOD_RECUR;
-
- assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL));
- }
-
- private boolean verifySaveEventModifyRecurring(ArrayList<ContentProviderOperation> ops) {
- ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
- int br_id = 0;
- mExpectedValues = buildTestValues();
- mExpectedValues.put(Events.HAS_ALARM, 0);
- // This is tested elsewhere, used for convenience here
- mHelper.checkTimeDependentFields(mModel2, mModel1, mExpectedValues,
- EditEventHelper.MODIFY_ALL);
-
- expectedOps.add(ContentProviderOperation.newUpdate(Uri.parse(mModel1.mUri)).withValues(
- mExpectedValues).build());
-
- // This call has a separate unit test so we'll use it to simplify making the expected vals
- mHelper.saveReminders(expectedOps, TEST_EVENT_ID, mModel1.mReminders,
- mModel2.mReminders, false);
-
- addOwnerAttendeeToOps(expectedOps);
- addAttendeeChangesOps(expectedOps);
-
- assertEquals(expectedOps, ops);
- return true;
- }
-
- @Smoke
- @SmallTest
- public void testSaveEventRecurringToNonRecurring() {
- // Creates an original and an updated recurring event model
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- mModel1 = buildTestModel();
- mModel2 = buildTestModel();
- mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
-
- // Updating a recurring event with a new attendee list
- mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
- // And a new start time to ensure the time fields aren't removed
- mModel1.mOriginalStart = TEST_START;
-
- // The original model is assumed correct so drop the no good bit
- mModel2.addAttendees(TEST_ADDRESSES4, null);
-
- // Replace an existing recurring event with a non-recurring event
- mModel1.mRrule = null;
- mModel1.mEnd = TEST_END;
- mCurrentSaveTest = SAVE_EVENT_RECUR_TO_NORECUR;
-
- assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL));
- }
-
- private boolean verifySaveEventRecurringToNonRecurring(ArrayList<ContentProviderOperation> ops)
- {
- ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
- int id = 0;
- mExpectedValues = buildNonRecurringTestValues();
- mExpectedValues.put(Events.HAS_ALARM, 0);
- // This is tested elsewhere, used for convenience here
- mHelper.checkTimeDependentFields(mModel1, mModel1, mExpectedValues,
- EditEventHelper.MODIFY_ALL);
-
- expectedOps.add(ContentProviderOperation.newDelete(Uri.parse(mModel1.mUri)).build());
- id = expectedOps.size();
- expectedOps.add(ContentProviderOperation
- .newInsert(Events.CONTENT_URI)
- .withValues(mExpectedValues)
- .build());
-
- mHelper.saveRemindersWithBackRef(expectedOps, id, mModel1.mReminders,
- mModel2.mReminders, true);
-
- addOwnerAttendeeToOps(expectedOps, id);
-
- addTestAttendees(expectedOps, true, id);
-
- assertEquals(expectedOps, ops);
- return true;
- }
-
- @Smoke
- @SmallTest
- public void testSaveEventNonRecurringToRecurring() {
- // Creates an original non-recurring and an updated recurring event model
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- mModel1 = buildTestModel();
- mModel2 = buildTestModel();
- mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
-
- // Updating a recurring event with a new attendee list
- mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
- // And a new start time to ensure the time fields aren't removed
- mModel1.mOriginalStart = TEST_START;
-
- // The original model is assumed correct so drop the no good bit
- mModel2.addAttendees(TEST_ADDRESSES4, null);
-
- mModel2.mRrule = null;
- mModel2.mEnd = TEST_END;
- mCurrentSaveTest = SAVE_EVENT_NORECUR_TO_RECUR;
-
- assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL));
- }
-
- private boolean verifySaveEventNonRecurringToRecurring(ArrayList<ContentProviderOperation> ops)
- {
- // Changing a non-recurring event to a recurring event should generate the same operations
- // as just modifying a recurring event.
- return verifySaveEventModifyRecurring(ops);
- }
-
- @Smoke
- @SmallTest
- public void testSaveEventUpdateNonRecurring() {
- // Creates an original non-recurring and an updated recurring event model
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- mModel1 = buildTestModel();
- mModel2 = buildTestModel();
- mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
-
- // Updating a recurring event with a new attendee list
- mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
- // And a new start time to ensure the time fields aren't removed
- mModel1.mOriginalStart = TEST_START;
-
- // The original model is assumed correct so drop the no good bit
- mModel2.addAttendees(TEST_ADDRESSES4, null);
-
- mModel2.mRrule = null;
- mModel2.mEnd = TEST_END2;
- mModel1.mRrule = null;
- mModel1.mEnd = TEST_END2;
- mCurrentSaveTest = SAVE_EVENT_MOD_NORECUR;
-
- assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL));
- }
-
- private boolean verifySaveEventUpdateNonRecurring(ArrayList<ContentProviderOperation> ops) {
- ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
- int id = TEST_EVENT_ID;
- mExpectedValues = buildNonRecurringTestValues();
- mExpectedValues.put(Events.HAS_ALARM, 0);
- // This is tested elsewhere, used for convenience here
- mHelper.checkTimeDependentFields(mModel1, mModel1, mExpectedValues,
- EditEventHelper.MODIFY_ALL);
- expectedOps.add(ContentProviderOperation.newUpdate(Uri.parse(mModel1.mUri)).withValues(
- mExpectedValues).build());
- // This call has a separate unit test so we'll use it to simplify making the expected vals
- mHelper.saveReminders(expectedOps, TEST_EVENT_ID, mModel1.mReminders,
- mModel2.mReminders, false);
- addOwnerAttendeeToOps(expectedOps);
- addAttendeeChangesOps(expectedOps);
-
- assertEquals(expectedOps, ops);
- return true;
- }
-
- @Smoke
- @SmallTest
- public void testSaveEventModifySingleInstance() {
- // Creates an original non-recurring and an updated recurring event model
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- mModel1 = buildTestModel();
- mModel2 = buildTestModel();
- mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
-
- mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
- // And a new start time to ensure the time fields aren't removed
- mModel1.mOriginalStart = TEST_START;
-
- // The original model is assumed correct so drop the no good bit
- mModel2.addAttendees(TEST_ADDRESSES4, null);
-
- // Modify the second instance of the event
- long dayInMs = EditEventHelper.DAY_IN_SECONDS*1000;
- mModel1.mRrule = null;
- mModel1.mEnd = TEST_END + dayInMs;
- mModel1.mStart += dayInMs;
- mModel1.mOriginalStart = mModel1.mStart;
-
- mCurrentSaveTest = SAVE_EVENT_MOD_INSTANCE;
- // Only modify this instance
- assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_SELECTED));
- }
-
- private boolean verifySaveEventModifySingleInstance(ArrayList<ContentProviderOperation> ops) {
- ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
- int id = 0;
- mExpectedValues = buildNonRecurringTestValues();
- mExpectedValues.put(Events.HAS_ALARM, 0);
- // This is tested elsewhere, used for convenience here
- mHelper.checkTimeDependentFields(mModel1, mModel1, mExpectedValues,
- EditEventHelper.MODIFY_ALL);
-
- moveExpectedTimeValuesForwardOneDay();
- mExpectedValues.put(Events.ORIGINAL_SYNC_ID, mModel2.mSyncId);
- mExpectedValues.put(Events.ORIGINAL_INSTANCE_TIME, mModel1.mOriginalStart);
- mExpectedValues.put(Events.ORIGINAL_ALL_DAY, 1);
-
- ContentProviderOperation.Builder b = ContentProviderOperation
- .newInsert(Events.CONTENT_URI)
- .withValues(mExpectedValues);
- expectedOps.add(b.build());
-
- mHelper.saveRemindersWithBackRef(expectedOps, id, mModel1.mReminders,
- mModel2.mReminders, true);
-
- addOwnerAttendeeToOps(expectedOps, id);
-
- addTestAttendees(expectedOps, true, id);
-
- assertEquals(expectedOps, ops);
- return true;
- }
-
- @Smoke
- @SmallTest
- public void testSaveEventModifyAllFollowingWithNonRecurring() {
- // Creates an original and an updated recurring event model. The update starts on the 2nd
- // instance of the original.
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- mModel1 = buildTestModel();
- mModel2 = buildTestModel();
- mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
-
- mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
- mModel2.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
-
- // The original model is assumed correct so drop the no good bit
- mModel2.addAttendees(TEST_ADDRESSES4, null);
-
- // Modify the second instance of the event
- long dayInMs = EditEventHelper.DAY_IN_SECONDS*1000;
- mModel1.mRrule = null;
- mModel1.mEnd = TEST_END + dayInMs;
- mModel1.mStart += dayInMs;
- mModel1.mOriginalStart = mModel1.mStart;
-
- mCurrentSaveTest = SAVE_EVENT_ALLFOLLOW_TO_NORECUR;
- // Only modify this instance
- assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL_FOLLOWING));
- }
-
- private boolean verifySaveEventModifyAllFollowingWithNonRecurring(
- ArrayList<ContentProviderOperation> ops) {
- ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
- int id = 0;
- mExpectedValues = buildNonRecurringTestValues();
- mExpectedValues.put(Events.HAS_ALARM, 0);
- moveExpectedTimeValuesForwardOneDay();
- // This has a separate test
- mHelper.updatePastEvents(expectedOps, mModel2, mModel1.mOriginalStart);
- id = expectedOps.size();
- expectedOps.add(ContentProviderOperation
- .newInsert(Events.CONTENT_URI)
- .withValues(mExpectedValues)
- .build());
-
- mHelper.saveRemindersWithBackRef(expectedOps, id, mModel1.mReminders,
- mModel2.mReminders, true);
-
- addOwnerAttendeeToOps(expectedOps, id);
-
- addTestAttendees(expectedOps, true, id);
-
- assertEquals(expectedOps, ops);
- return true;
- }
-
- @Smoke
- @SmallTest
- public void testSaveEventModifyAllFollowingFirstWithNonRecurring() {
- // Creates an original recurring and an updated non-recurring event model for the first
- // instance. This should replace the original event with a non-recurring event.
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- mModel1 = buildTestModel();
- mModel2 = buildTestModel();
- mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
-
- mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
- mModel2.mUri = mModel1.mUri;
- // And a new start time to ensure the time fields aren't removed
- mModel1.mOriginalStart = TEST_START;
-
- // The original model is assumed correct so drop the no good bit
- mModel2.addAttendees(TEST_ADDRESSES3, null);
-
- // Move the event one day but keep original start set to the first instance
- long dayInMs = EditEventHelper.DAY_IN_SECONDS*1000;
- mModel1.mRrule = null;
- mModel1.mEnd = TEST_END + dayInMs;
- mModel1.mStart += dayInMs;
-
- mCurrentSaveTest = SAVE_EVENT_FIRST_TO_NORECUR;
- // Only modify this instance
- assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL_FOLLOWING));
- }
-
- private boolean verifySaveEventModifyAllFollowingFirstWithNonRecurring(
- ArrayList<ContentProviderOperation> ops) {
-
- ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
- int id = 0;
- mExpectedValues = buildNonRecurringTestValues();
- mExpectedValues.put(Events.HAS_ALARM, 0);
- moveExpectedTimeValuesForwardOneDay();
-
- expectedOps.add(ContentProviderOperation.newDelete(Uri.parse(mModel1.mUri)).build());
- id = expectedOps.size();
- expectedOps.add(ContentProviderOperation
- .newInsert(Events.CONTENT_URI)
- .withValues(mExpectedValues)
- .build());
-
- mHelper.saveRemindersWithBackRef(expectedOps, id, mModel1.mReminders,
- mModel2.mReminders, true);
-
- addOwnerAttendeeToOps(expectedOps, id);
-
- addTestAttendees(expectedOps, true, id);
-
- assertEquals(expectedOps, ops);
- return true;
- }
-
- @Smoke
- @SmallTest
- public void testSaveEventModifyAllFollowingFirstWithRecurring() {
- // Creates an original recurring and an updated recurring event model for the first instance
- // This should replace the original event with a new recurrence
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- mModel1 = buildTestModel();
- mModel2 = buildTestModel();
- mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
-
- mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
- mModel2.mUri = mModel1.mUri;
- // And a new start time to ensure the time fields aren't removed
- mModel1.mOriginalStart = TEST_START;
-
- // The original model is assumed correct so drop the no good bit
- mModel2.addAttendees(TEST_ADDRESSES4, null);
-
- // Move the event one day but keep original start set to the first instance
- long dayInMs = EditEventHelper.DAY_IN_SECONDS*1000;
- mModel1.mStart += dayInMs;
-
- mCurrentSaveTest = SAVE_EVENT_FIRST_TO_RECUR;
- // Only modify this instance
- assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL_FOLLOWING));
- }
-
- private boolean verifySaveEventModifyAllFollowingFirstWithRecurring(
- ArrayList<ContentProviderOperation> ops) {
- ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
- int br_id = 0;
- mExpectedValues = buildTestValues();
- mExpectedValues.put(Events.HAS_ALARM, 0);
- moveExpectedTimeValuesForwardOneDay();
- mExpectedValues.put(Events.DTEND, (Long)null);
- // This is tested elsewhere, used for convenience here
- mHelper.checkTimeDependentFields(mModel2, mModel1, mExpectedValues,
- EditEventHelper.MODIFY_ALL_FOLLOWING);
-
- expectedOps.add(ContentProviderOperation.newUpdate(Uri.parse(mModel1.mUri)).withValues(
- mExpectedValues).build());
-
- // This call has a separate unit test so we'll use it to simplify making the expected vals
- mHelper.saveReminders(expectedOps, TEST_EVENT_ID, mModel1.mReminders,
- mModel2.mReminders, true);
-
- addOwnerAttendeeToOps(expectedOps);
- addAttendeeChangesOps(expectedOps);
-
- assertEquals(expectedOps, ops);
- return true;
- }
-
- @Smoke
- @SmallTest
- public void testSaveEventModifyAllFollowingWithRecurring() {
- // Creates an original recurring and an updated recurring event model
- // for the second instance. This should end the original recurrence and add a new
- // recurrence.
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- mModel1 = buildTestModel();
- mModel2 = buildTestModel();
- mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
-
- mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
- mModel2.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
-
- // The original model is assumed correct so drop the no good bit
- mModel2.addAttendees(TEST_ADDRESSES4, null);
-
- // Move the event one day and the original start so it references the second instance
- long dayInMs = EditEventHelper.DAY_IN_SECONDS*1000;
- mModel1.mStart += dayInMs;
- mModel1.mOriginalStart = mModel1.mStart;
-
- mCurrentSaveTest = SAVE_EVENT_ALLFOLLOW_TO_RECUR;
- // Only modify this instance
- assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL_FOLLOWING));
- }
-
- private boolean verifySaveEventModifyAllFollowingWithRecurring(
- ArrayList<ContentProviderOperation> ops) {
- ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
- int br_id = 0;
- mExpectedValues = buildTestValues();
- mExpectedValues.put(Events.HAS_ALARM, 0);
- moveExpectedTimeValuesForwardOneDay();
- mExpectedValues.put(Events.DTEND, (Long)null);
- // This is tested elsewhere, used for convenience here
- mHelper.updatePastEvents(expectedOps, mModel2, mModel1.mOriginalStart);
-
- br_id = expectedOps.size();
- expectedOps.add(ContentProviderOperation
- .newInsert(Events.CONTENT_URI)
- .withValues(mExpectedValues)
- .build());
-
- // This call has a separate unit test so we'll use it to simplify making the expected vals
- mHelper.saveRemindersWithBackRef(expectedOps, br_id, mModel1.mReminders,
- mModel2.mReminders, true);
-
- addOwnerAttendeeToOps(expectedOps, br_id);
-
- addTestAttendees(expectedOps, true, br_id);
-
- assertEquals(expectedOps, ops);
- return true;
- }
-
- @Smoke
- @SmallTest
- public void testGetAddressesFromList() {
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- LinkedHashSet<Rfc822Token> expected = new LinkedHashSet<Rfc822Token>();
- expected.add(new Rfc822Token(null, "ad1@email.com", ""));
- expected.add(new Rfc822Token("First Last", "first@email.com", "comment"));
- expected.add(new Rfc822Token(null, "one.two.three@email.grue", ""));
-
- LinkedHashSet<Rfc822Token> actual = mHelper.getAddressesFromList(TEST_ADDRESSES,
- new Rfc822Validator(null));
- assertEquals(expected, actual);
- }
-
- @Smoke
- @SmallTest
- public void testConstructDefaultStartTime() {
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- long now = 0;
- long expected = now + 30 * DateUtils.MINUTE_IN_MILLIS;
- assertEquals(expected, mHelper.constructDefaultStartTime(now));
-
- // 2:00 -> 2:30
- now = 1262340000000L; // Fri Jan 01 2010 02:00:00 GMT-0800 (PST)
- expected = now + 30 * DateUtils.MINUTE_IN_MILLIS;
- assertEquals(expected, mHelper.constructDefaultStartTime(now));
-
- // 2:01 -> 2:30
- now += DateUtils.MINUTE_IN_MILLIS;
- assertEquals(expected, mHelper.constructDefaultStartTime(now));
-
- // 2:02 -> 2:30
- now += DateUtils.MINUTE_IN_MILLIS;
- assertEquals(expected, mHelper.constructDefaultStartTime(now));
-
- // 2:32 -> 3:00
- now += 30 * DateUtils.MINUTE_IN_MILLIS;
- expected += 30 * DateUtils.MINUTE_IN_MILLIS;
- assertEquals(expected, mHelper.constructDefaultStartTime(now));
-
- // 2:33 -> 3:00
- now += DateUtils.MINUTE_IN_MILLIS;
- assertEquals(expected, mHelper.constructDefaultStartTime(now));
-
- }
-
- @Smoke
- @SmallTest
- public void testConstructDefaultEndTime() {
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- long start = 1262340000000L;
- long expected = start + DateUtils.HOUR_IN_MILLIS;
- assertEquals(expected, mHelper.constructDefaultEndTime(start));
- }
-
- @Smoke
- @SmallTest
- public void testCheckTimeDependentFieldsNoChanges() {
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- mModel1 = buildTestModel();
- mModel2 = buildTestModel();
- mModel2.mRrule = null;
-
- mValues = buildTestValues();
- mExpectedValues = buildTestValues();
-
- // if any time/recurrence vals are different but there's no new rrule it
- // shouldn't change
- mHelper.checkTimeDependentFields(mModel1, mModel2, mValues, EditEventHelper.MODIFY_ALL);
- assertEquals(mExpectedValues, mValues);
-
- // also, if vals are different and it's not modifying all it shouldn't
- // change.
- mModel2.mRrule = "something else";
- mHelper.checkTimeDependentFields(mModel1, mModel2, mValues,
- EditEventHelper.MODIFY_SELECTED);
- assertEquals(mExpectedValues, mValues);
-
- // if vals changed and modify all is selected dtstart should be updated
- // by the difference
- // between originalStart and start
- mModel2.mOriginalStart = mModel2.mStart + 60000; // set the old time to
- // one minute later
- mModel2.mStart += 120000; // move the event another 1 minute.
-
- // shouldn't change for an allday event
- // expectedVals.put(Events.DTSTART, mModel1.mStart + 60000); // should
- // now be 1 minute later
- // dtstart2 shouldn't change since it gets rezeroed in the local
- // timezone for allDay events
-
- mHelper.checkTimeDependentFields(mModel1, mModel2, mValues,
- EditEventHelper.MODIFY_SELECTED);
- assertEquals(mExpectedValues, mValues);
- }
-
- @Smoke
- @SmallTest
- public void testCheckTimeDependentFieldsChanges() {
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- mModel1 = buildTestModel();
- mModel2 = buildTestModel();
- mModel2.mRrule = null;
-
- mValues = buildTestValues();
- mExpectedValues = buildTestValues();
-
- // if all the time values are the same it should remove them from vals
- mModel2.mRrule = mModel1.mRrule;
- mModel2.mStart = mModel1.mStart;
- mModel2.mOriginalStart = mModel2.mStart;
-
- mExpectedValues.remove(Events.DTSTART);
- mExpectedValues.remove(Events.DTEND);
- mExpectedValues.remove(Events.DURATION);
- mExpectedValues.remove(Events.ALL_DAY);
- mExpectedValues.remove(Events.RRULE);
- mExpectedValues.remove(Events.EVENT_TIMEZONE);
-
- mHelper.checkTimeDependentFields(mModel1, mModel2, mValues,
- EditEventHelper.MODIFY_SELECTED);
- assertEquals(mExpectedValues, mValues);
-
- }
-
- @Smoke
- @SmallTest
- public void testUpdatePastEvents() {
- ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
- ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
- long initialBeginTime = 1472864400000L; // Sep 3, 2016, 12AM UTC time
- mValues = new ContentValues();
-
- mModel1 = buildTestModel();
- mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
-
- mValues.put(Events.RRULE, "FREQ=DAILY;UNTIL=20160903;WKST=SU"); // yyyymmddThhmmssZ
- mValues.put(Events.DTSTART, TEST_START);
-
- ContentProviderOperation.Builder b = ContentProviderOperation.newUpdate(
- Uri.parse(mModel1.mUri)).withValues(mValues);
- expectedOps.add(b.build());
-
- mHelper.updatePastEvents(ops, mModel1, initialBeginTime);
- assertEquals(expectedOps, ops);
-
- mModel1.mAllDay = false;
-
- mValues.put(Events.RRULE, "FREQ=DAILY;UNTIL=20160903T005959Z;WKST=SU"); // yyyymmddThhmmssZ
-
- expectedOps.clear();
- b = ContentProviderOperation.newUpdate(Uri.parse(mModel1.mUri)).withValues(mValues);
- expectedOps.add(b.build());
-
- ops.clear();
- mHelper.updatePastEvents(ops, mModel1, initialBeginTime);
- assertEquals(expectedOps, ops);
- }
-
- @Smoke
- @SmallTest
- public void testConstructReminderLabel() {
- mActivity = buildTestContext();
-
- String label = EventViewUtils.constructReminderLabel(mActivity, 35, true);
- assertEquals("35 mins", label);
-
- label = EventViewUtils.constructReminderLabel(mActivity, 72, false);
- assertEquals("72 minutes", label);
-
- label = EventViewUtils.constructReminderLabel(mActivity, 60, true);
- assertEquals("1 hours", label);
-
- label = EventViewUtils.constructReminderLabel(mActivity, 60 * 48, true);
- assertEquals("2 days", label);
- }
-
- @Smoke
- @SmallTest
- public void testIsSameEvent() {
- mModel1 = new CalendarEventModel();
- mModel2 = new CalendarEventModel();
-
- mModel1.mId = 1;
- mModel1.mCalendarId = 1;
- mModel2.mId = 1;
- mModel2.mCalendarId = 1;
-
- // considered the same if the event and calendar ids both match
- assertTrue(EditEventHelper.isSameEvent(mModel1, mModel2));
-
- mModel2.mId = 2;
- assertFalse(EditEventHelper.isSameEvent(mModel1, mModel2));
-
- mModel2.mId = 1;
- mModel2.mCalendarId = 2;
- assertFalse(EditEventHelper.isSameEvent(mModel1, mModel2));
- }
-
- @Smoke
- @SmallTest
- public void testSaveReminders() {
- ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
- ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
- long eventId = TEST_EVENT_ID;
- ArrayList<ReminderEntry> reminders = new ArrayList<ReminderEntry>();
- ArrayList<ReminderEntry> originalReminders = new ArrayList<ReminderEntry>();
- boolean forceSave = true;
- boolean result;
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
- assertNotNull(mHelper);
-
- // First test forcing a delete with no reminders.
- String where = Reminders.EVENT_ID + "=?";
- String[] args = new String[] {Long.toString(eventId)};
- ContentProviderOperation.Builder b =
- ContentProviderOperation.newDelete(Reminders.CONTENT_URI);
- b.withSelection(where, args);
- expectedOps.add(b.build());
-
- result = mHelper.saveReminders(ops, eventId, reminders, originalReminders, forceSave);
- assertTrue(result);
- assertEquals(expectedOps, ops);
-
- // Now test calling save with identical reminders and no forcing
- reminders.add(ReminderEntry.valueOf(5));
- reminders.add(ReminderEntry.valueOf(10));
- reminders.add(ReminderEntry.valueOf(15));
-
- originalReminders.add(ReminderEntry.valueOf(5));
- originalReminders.add(ReminderEntry.valueOf(10));
- originalReminders.add(ReminderEntry.valueOf(15));
-
- forceSave = false;
-
- ops.clear();
-
- // Should fail to create any ops since nothing changed
- result = mHelper.saveReminders(ops, eventId, reminders, originalReminders, forceSave);
- assertFalse(result);
- assertEquals(0, ops.size());
-
- //Now test adding a single reminder
- originalReminders.remove(2);
-
- addExpectedMinutes(expectedOps);
-
- result = mHelper.saveReminders(ops, eventId, reminders, originalReminders, forceSave);
- assertTrue(result);
- assertEquals(expectedOps, ops);
- }
-
- @Smoke
- @SmallTest
- public void testSaveRemindersWithBackRef() {
- ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
- ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
- long eventId = TEST_EVENT_ID;
- ArrayList<ReminderEntry> reminders = new ArrayList<ReminderEntry>();
- ArrayList<ReminderEntry> originalReminders = new ArrayList<ReminderEntry>();
- boolean forceSave = true;
- boolean result;
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
- assertNotNull(mHelper);
-
- // First test forcing a delete with no reminders.
- ContentProviderOperation.Builder b =
- ContentProviderOperation.newDelete(Reminders.CONTENT_URI);
- b.withSelection(Reminders.EVENT_ID + "=?", new String[1]);
- b.withSelectionBackReference(0, TEST_EVENT_INDEX_ID);
- expectedOps.add(b.build());
-
- result =
- mHelper.saveRemindersWithBackRef(ops, TEST_EVENT_INDEX_ID, reminders,
- originalReminders, forceSave);
- assertTrue(result);
- assertEquals(expectedOps, ops);
-
- // Now test calling save with identical reminders and no forcing
- reminders.add(ReminderEntry.valueOf(5));
- reminders.add(ReminderEntry.valueOf(10));
- reminders.add(ReminderEntry.valueOf(15));
-
- originalReminders.add(ReminderEntry.valueOf(5));
- originalReminders.add(ReminderEntry.valueOf(10));
- originalReminders.add(ReminderEntry.valueOf(15));
-
- forceSave = false;
-
- ops.clear();
-
- result = mHelper.saveRemindersWithBackRef(ops, ops.size(), reminders, originalReminders,
- forceSave);
- assertFalse(result);
- assertEquals(0, ops.size());
-
- //Now test adding a single reminder
- originalReminders.remove(2);
-
- addExpectedMinutesWithBackRef(expectedOps);
-
- result = mHelper.saveRemindersWithBackRef(ops, ops.size(), reminders, originalReminders,
- forceSave);
- assertTrue(result);
- assertEquals(expectedOps, ops);
- }
-
- @Smoke
- @SmallTest
- public void testIsFirstEventInSeries() {
- mModel1 = new CalendarEventModel();
- mModel2 = new CalendarEventModel();
-
- // It's considered the first event if the original start of the new model matches the
- // start of the old model
- mModel1.mOriginalStart = 100;
- mModel1.mStart = 200;
- mModel2.mOriginalStart = 100;
- mModel2.mStart = 100;
-
- assertTrue(EditEventHelper.isFirstEventInSeries(mModel1, mModel2));
-
- mModel1.mOriginalStart = 80;
- assertFalse(EditEventHelper.isFirstEventInSeries(mModel1, mModel2));
- }
-
- @Smoke
- @SmallTest
- public void testAddRecurrenceRule() {
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
- mValues = new ContentValues();
- mExpectedValues = new ContentValues();
- mModel1 = new CalendarEventModel();
-
- mExpectedValues.put(Events.RRULE, "Weekly, Monday");
- mExpectedValues.put(Events.DURATION, "P60S");
- mExpectedValues.put(Events.DTEND, (Long) null);
-
- mModel1.mRrule = "Weekly, Monday";
- mModel1.mStart = 1;
- mModel1.mEnd = 60001;
- mModel1.mAllDay = false;
-
- mHelper.addRecurrenceRule(mValues, mModel1);
- assertEquals(mExpectedValues, mValues);
-
- mExpectedValues.put(Events.DURATION, "P1D");
-
- mModel1.mAllDay = true;
- mValues.clear();
-
- mHelper.addRecurrenceRule(mValues, mModel1);
- assertEquals(mExpectedValues, mValues);
-
- }
-
- @Smoke
- @SmallTest
- public void testUpdateRecurrenceRule() {
- int selection = EditEventHelper.DOES_NOT_REPEAT;
- int weekStart = Calendar.SUNDAY;
- mModel1 = new CalendarEventModel();
- mModel1.mTimezone = Time.TIMEZONE_UTC;
- mModel1.mStart = 1272665741000L; // Fri, April 30th ~ 3:17PM
-
- mModel1.mRrule = "This should go away";
-
- EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
- assertNull(mModel1.mRrule);
-
- mModel1.mRrule = "This shouldn't change";
- selection = EditEventHelper.REPEATS_CUSTOM;
-
- EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
- assertEquals("This shouldn't change", mModel1.mRrule);
-
- selection = EditEventHelper.REPEATS_DAILY;
-
- EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
- assertEquals("FREQ=DAILY;WKST=SU", mModel1.mRrule);
-
- selection = EditEventHelper.REPEATS_EVERY_WEEKDAY;
-
- EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
- assertEquals("FREQ=WEEKLY;WKST=SU;BYDAY=MO,TU,WE,TH,FR", mModel1.mRrule);
-
- selection = EditEventHelper.REPEATS_WEEKLY_ON_DAY;
-
- EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
- assertEquals("FREQ=WEEKLY;WKST=SU;BYDAY=FR", mModel1.mRrule);
-
- selection = EditEventHelper.REPEATS_MONTHLY_ON_DAY;
-
- EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
- assertEquals("FREQ=MONTHLY;WKST=SU;BYMONTHDAY=30", mModel1.mRrule);
-
- selection = EditEventHelper.REPEATS_MONTHLY_ON_DAY_COUNT;
-
- EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
- assertEquals("FREQ=MONTHLY;WKST=SU;BYDAY=-1FR", mModel1.mRrule);
-
- selection = EditEventHelper.REPEATS_YEARLY;
-
- EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
- assertEquals("FREQ=YEARLY;WKST=SU", mModel1.mRrule);
- }
-
- @Smoke
- @SmallTest
- public void testSetModelFromCursor() {
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
- MatrixCursor c = new MatrixCursor(EditEventHelper.EVENT_PROJECTION);
- c.addRow(TEST_CURSOR_DATA);
-
- mModel1 = new CalendarEventModel();
- mModel2 = buildTestModel();
-
- EditEventHelper.setModelFromCursor(mModel1, c);
- assertEquals(mModel1, mModel2);
-
- TEST_CURSOR_DATA[EditEventHelper.EVENT_INDEX_ALL_DAY] = "0";
- c.close();
- c = new MatrixCursor(EditEventHelper.EVENT_PROJECTION);
- c.addRow(TEST_CURSOR_DATA);
-
- mModel2.mAllDay = false;
- mModel2.mStart = TEST_START; // UTC time
-
- EditEventHelper.setModelFromCursor(mModel1, c);
- assertEquals(mModel1, mModel2);
-
- TEST_CURSOR_DATA[EditEventHelper.EVENT_INDEX_RRULE] = null;
- c.close();
- c = new MatrixCursor(EditEventHelper.EVENT_PROJECTION);
- c.addRow(TEST_CURSOR_DATA);
-
- mModel2.mRrule = null;
- mModel2.mEnd = TEST_END;
- mModel2.mDuration = null;
-
- EditEventHelper.setModelFromCursor(mModel1, c);
- assertEquals(mModel1, mModel2);
-
- TEST_CURSOR_DATA[EditEventHelper.EVENT_INDEX_ALL_DAY] = "1";
- c.close();
- c = new MatrixCursor(EditEventHelper.EVENT_PROJECTION);
- c.addRow(TEST_CURSOR_DATA);
-
- mModel2.mAllDay = true;
- mModel2.mStart = TEST_START; // Monday, May 3rd, midnight
- mModel2.mEnd = TEST_END; // Tuesday, May 4th, midnight
-
- EditEventHelper.setModelFromCursor(mModel1, c);
- assertEquals(mModel1, mModel2);
- }
-
- @Smoke
- @SmallTest
- public void testGetContentValuesFromModel() {
- mActivity = buildTestContext();
- mHelper = new EditEventHelper(mActivity, null);
- mExpectedValues = buildTestValues();
- mModel1 = buildTestModel();
-
- ContentValues values = mHelper.getContentValuesFromModel(mModel1);
- assertEquals(mExpectedValues, values);
-
- mModel1.mRrule = null;
- mModel1.mEnd = TEST_END;
-
- mExpectedValues.put(Events.RRULE, (String) null);
- mExpectedValues.put(Events.DURATION, (String) null);
- mExpectedValues.put(Events.DTEND, TEST_END); // UTC time
-
- values = mHelper.getContentValuesFromModel(mModel1);
- assertEquals(mExpectedValues, values);
-
- mModel1.mAllDay = false;
-
- mExpectedValues.put(Events.ALL_DAY, 0);
- mExpectedValues.put(Events.DTSTART, TEST_START);
- mExpectedValues.put(Events.DTEND, TEST_END);
- // not an allday event so timezone isn't modified
- mExpectedValues.put(Events.EVENT_TIMEZONE, "UTC");
-
- values = mHelper.getContentValuesFromModel(mModel1);
- assertEquals(mExpectedValues, values);
- }
-
- @Smoke
- @SmallTest
- public void testExtractDomain() {
- String domain = EditEventHelper.extractDomain("test.email@gmail.com");
- assertEquals("gmail.com", domain);
-
- domain = EditEventHelper.extractDomain("bademail.no#$%at symbol");
- assertNull(domain);
- }
-
- private void addExpectedMinutes(ArrayList<ContentProviderOperation> expectedOps) {
- ContentProviderOperation.Builder b;
- mValues = new ContentValues();
-
- mValues.clear();
- mValues.put(Reminders.MINUTES, 5);
- mValues.put(Reminders.METHOD, Reminders.METHOD_DEFAULT);
- mValues.put(Reminders.EVENT_ID, TEST_EVENT_ID);
- b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(mValues);
- expectedOps.add(b.build());
-
- mValues.clear();
- mValues.put(Reminders.MINUTES, 10);
- mValues.put(Reminders.METHOD, Reminders.METHOD_DEFAULT);
- mValues.put(Reminders.EVENT_ID, TEST_EVENT_ID);
- b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(mValues);
- expectedOps.add(b.build());
-
- mValues.clear();
- mValues.put(Reminders.MINUTES, 15);
- mValues.put(Reminders.METHOD, Reminders.METHOD_DEFAULT);
- mValues.put(Reminders.EVENT_ID, TEST_EVENT_ID);
- b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(mValues);
- expectedOps.add(b.build());
- }
-
- private void addExpectedMinutesWithBackRef(ArrayList<ContentProviderOperation> expectedOps) {
- ContentProviderOperation.Builder b;
- mValues = new ContentValues();
-
- mValues.clear();
- mValues.put(Reminders.MINUTES, 5);
- mValues.put(Reminders.METHOD, Reminders.METHOD_DEFAULT);
- b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(mValues);
- b.withValueBackReference(Reminders.EVENT_ID, TEST_EVENT_INDEX_ID);
- expectedOps.add(b.build());
-
- mValues.clear();
- mValues.put(Reminders.MINUTES, 10);
- mValues.put(Reminders.METHOD, Reminders.METHOD_DEFAULT);
- b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(mValues);
- b.withValueBackReference(Reminders.EVENT_ID, TEST_EVENT_INDEX_ID);
- expectedOps.add(b.build());
-
- mValues.clear();
- mValues.put(Reminders.MINUTES, 15);
- mValues.put(Reminders.METHOD, Reminders.METHOD_DEFAULT);
- b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(mValues);
- b.withValueBackReference(Reminders.EVENT_ID, TEST_EVENT_INDEX_ID);
- expectedOps.add(b.build());
- }
-
- private static void assertEquals(ArrayList<ContentProviderOperation> expected,
- ArrayList<ContentProviderOperation> actual) {
- if (expected == null) {
- assertNull(actual);
- }
- int size = expected.size();
-
- assertEquals(size, actual.size());
-
- for (int i = 0; i < size; i++) {
- assertTrue("At index " + i + ", expected:\n" + String.valueOf(expected.get(i)) +
- "\nActual:\n" + String.valueOf(actual.get(i)),
- cpoEquals(expected.get(i), actual.get(i)));
- }
-
- }
-
- private static boolean cpoEquals(ContentProviderOperation cpo1, ContentProviderOperation cpo2) {
- if (cpo1 == null && cpo2 != null) {
- return false;
- }
- if (cpo1 == cpo2) {
- return true;
- }
- if (cpo2 == null) {
- return false;
- }
-
- // It turns out we can't trust the toString() of the ContentProviderOperations to be
- // consistent, so we have to do the comparison manually.
- //
- // Start by splitting by commas, so that we can compare each key-value pair individually.
- String[] operations1 = cpo1.toString().split(",");
- String[] operations2 = cpo2.toString().split(",");
- // The two numbers of operations must be equal.
- if (operations1.length != operations2.length) {
- return false;
- }
- // Iterate through the key-value pairs and separate out the key and value.
- // The value may be either a single string, or a series of further key-value pairs
- // that are separated by " ", with a "=" between the key and value.
- for (int i = 0; i < operations1.length; i++) {
- String operation1 = operations1[i];
- String operation2 = operations2[i];
- // Limit the array to length 2 in case a ":" appears in the value.
- String[] keyValue1 = operation1.split(":", 2);
- String[] keyValue2 = operation2.split(":", 2);
- // If the key doesn't match, return false.
- if (!keyValue1[0].equals(keyValue2[0])) {
- return false;
- }
- // First just check if the value matches up. If so, we're good to go.
- if (keyValue1[1].equals(keyValue2[1])) {
- continue;
- }
- // If not, we need to try splitting the value by " " and sorting those keyvalue pairs.
- // Note that these are trimmed first to ensure we're not thrown off by extra whitespace.
- String[] valueKeyValuePairs1 = keyValue1[1].trim().split(" ");
- String[] valueKeyValuePairs2 = keyValue2[1].trim().split(" ");
- // Sort the value's keyvalue pairs alphabetically, and now compare them to each other.
- Arrays.sort(valueKeyValuePairs1);
- Arrays.sort(valueKeyValuePairs2);
- for (int j = 0; j < valueKeyValuePairs1.length; j++) {
- if (!valueKeyValuePairs1[j].equals(valueKeyValuePairs2[j])) {
- return false;
- }
- }
- }
-
- // If we make it all the way through without finding anything different, return true.
- return true;
- }
-
- // Generates a default model for testing. Should match up with
- // generateTestValues
- private CalendarEventModel buildTestModel() {
- CalendarEventModel model = new CalendarEventModel();
- model.mId = TEST_EVENT_ID;
- model.mTitle = "The_Question";
- model.mDescription = "Evaluating_Life_the_Universe_and_Everything";
- model.mLocation = "Earth_Mk2";
- model.mAllDay = true;
- model.mHasAlarm = false;
- model.mCalendarId = 2;
- model.mStart = TEST_START; // Monday, May 3rd, local Time
- model.mDuration = "P3652421990D";
- // The model uses the local timezone for allday
- model.mTimezone = "UTC";
- model.mRrule = "FREQ=DAILY;WKST=SU";
- model.mSyncId = "unique_per_calendar_stuff";
- model.mAvailability = 0;
- model.mAccessLevel = 2; // This is one less than the values written if >0
- model.mOwnerAccount = "steve@gmail.com";
- model.mHasAttendeeData = true;
- model.mOrganizer = "organizer@gmail.com";
- model.mIsOrganizer = false;
- model.mGuestsCanModify = false;
- model.mEventStatus = Events.STATUS_CONFIRMED;
- int displayColor = Utils.getDisplayColorFromColor(-2350809);
- model.setEventColor(displayColor);
- model.mCalendarAccountName = "steve.owner@gmail.com";
- model.mCalendarAccountType = "gmail.com";
- EventColorCache cache = new EventColorCache();
- cache.insertColor("steve.owner@gmail.com", "gmail.com", displayColor, 12);
- model.mEventColorCache = cache;
- model.mModelUpdatedWithEventCursor = true;
- return model;
- }
-
- // Generates a default set of values for testing. Should match up with
- // generateTestModel
- private ContentValues buildTestValues() {
- ContentValues values = new ContentValues();
-
- values.put(Events.CALENDAR_ID, 2L);
- values.put(Events.EVENT_TIMEZONE, "UTC"); // Allday events are converted
- // to UTC for the db
- values.put(Events.TITLE, "The_Question");
- values.put(Events.ALL_DAY, 1);
- values.put(Events.DTSTART, TEST_START); // Monday, May 3rd, midnight UTC time
- values.put(Events.HAS_ATTENDEE_DATA, 1);
-
- values.put(Events.RRULE, "FREQ=DAILY;WKST=SU");
- values.put(Events.DURATION, "P3652421990D");
- values.put(Events.DTEND, (Long) null);
- values.put(Events.DESCRIPTION, "Evaluating_Life_the_Universe_and_Everything");
- values.put(Events.EVENT_LOCATION, "Earth_Mk2");
- values.put(Events.AVAILABILITY, 0);
- values.put(Events.STATUS, Events.STATUS_CONFIRMED);
- values.put(Events.ACCESS_LEVEL, 3); // This is one more than the model if
- // >0
- values.put(Events.EVENT_COLOR_KEY, 12);
-
- return values;
- }
-
- private ContentValues buildNonRecurringTestValues() {
- ContentValues values = buildTestValues();
- values.put(Events.DURATION, (String)null);
- values.put(Events.DTEND, TEST_END);
- values.put(Events.RRULE, (String)null);
- return values;
- }
-
- // This gets called by EditEventHelper to read or write the data
- class TestProvider extends ContentProvider {
- int index = 0;
-
- public TestProvider() {
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String orderBy) {
- return null;
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- return 0;
- }
-
- @Override
- public String getType(Uri uri) {
- return null;
- }
-
- @Override
- public boolean onCreate() {
- return false;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- // TODO Auto-generated method stub
- return 0;
- }
- }
-
-}
diff --git a/tests/src/com/android/calendar/widget/CalendarAppWidgetServiceTest.java b/tests/src/com/android/calendar/widget/CalendarAppWidgetServiceTest.java
index 7a569f0f..4b0a0918 100644
--- a/tests/src/com/android/calendar/widget/CalendarAppWidgetServiceTest.java
+++ b/tests/src/com/android/calendar/widget/CalendarAppWidgetServiceTest.java
@@ -28,6 +28,7 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.test.suitebuilder.annotation.Suppress;
import android.text.format.DateUtils;
import android.text.format.Time;
+import android.util.Log;
import android.view.View;
import java.util.TimeZone;
@@ -163,13 +164,14 @@ public class CalendarAppWidgetServiceTest extends AndroidTestCase {
DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL);
eventInfo.where = location + i;
eventInfo.title = title + i;
- expected.mEventInfos.add(eventInfo);
cursor.addRow(getRow(1, start, end, title + i, location + i, 0));
// Test
CalendarAppWidgetModel actual = CalendarAppWidgetService.CalendarFactory.buildAppWidgetModel(
context, cursor, Time.getCurrentTimezone());
+ Log.e("Test", " expected: " + expected.toString()
+ + " actual: " + actual.toString());
assertEquals(expected.toString(), actual.toString());
}