blob: e73482cfa6abdd7ad872ac0b672b95e149cf5413 [file] [log] [blame]
Mason Tang2bebde72010-08-04 17:20:24 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.calendar;
18
Michael Chan2c8485c2012-05-09 10:23:45 -070019import static android.provider.CalendarContract.EXTRA_EVENT_ALL_DAY;
20import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
21import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
22import static com.android.calendar.CalendarController.EVENT_EDIT_ON_LAUNCH;
Mason Tang2bebde72010-08-04 17:20:24 -070023
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -080024import android.animation.Animator;
25import android.animation.AnimatorListenerAdapter;
26import android.animation.ObjectAnimator;
Mason Tang2bebde72010-08-04 17:20:24 -070027import android.app.Activity;
Michael Chan71d08832010-08-25 18:28:59 -070028import android.app.Dialog;
29import android.app.DialogFragment;
James Kung95e95382013-03-20 12:14:33 -070030import android.app.FragmentManager;
Andy McFaddenef31a982011-06-09 07:38:56 -070031import android.app.Service;
Mason Tang2bebde72010-08-04 17:20:24 -070032import android.content.ActivityNotFoundException;
Erik364309f2010-12-23 14:26:26 -080033import android.content.ContentProviderOperation;
Mason Tang2bebde72010-08-04 17:20:24 -070034import android.content.ContentResolver;
35import android.content.ContentUris;
36import android.content.ContentValues;
37import android.content.Context;
Isaac Katzenelsonb0a313a2011-10-24 11:41:56 -070038import android.content.DialogInterface;
Mason Tang2bebde72010-08-04 17:20:24 -070039import android.content.Intent;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -070040import android.content.SharedPreferences;
Michael Chan2c8485c2012-05-09 10:23:45 -070041import android.content.pm.ApplicationInfo;
42import android.content.pm.PackageManager;
43import android.content.pm.PackageManager.NameNotFoundException;
Mason Tang2bebde72010-08-04 17:20:24 -070044import android.content.res.Resources;
45import android.database.Cursor;
James Kung4afba182012-12-18 23:12:08 -080046import android.graphics.Color;
Mason Tang2bebde72010-08-04 17:20:24 -070047import android.graphics.Rect;
Michael Chan2c8485c2012-05-09 10:23:45 -070048import android.graphics.drawable.Drawable;
Mason Tang2bebde72010-08-04 17:20:24 -070049import android.net.Uri;
50import android.os.Bundle;
RoboErika7c03902011-06-14 11:06:44 -070051import android.provider.CalendarContract;
52import android.provider.CalendarContract.Attendees;
53import android.provider.CalendarContract.Calendars;
James Kung4afba182012-12-18 23:12:08 -080054import android.provider.CalendarContract.Colors;
RoboErika7c03902011-06-14 11:06:44 -070055import android.provider.CalendarContract.Events;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -070056import android.provider.CalendarContract.Reminders;
Erikcb811892010-09-28 13:44:19 -070057import android.provider.ContactsContract;
Mason Tang2bebde72010-08-04 17:20:24 -070058import android.provider.ContactsContract.CommonDataKinds;
Mason Tang2bebde72010-08-04 17:20:24 -070059import android.provider.ContactsContract.Intents;
Mason Tang2bebde72010-08-04 17:20:24 -070060import android.provider.ContactsContract.QuickContact;
Michael Chan8ce3b7d2010-09-01 15:41:01 -070061import android.text.Spannable;
62import android.text.SpannableStringBuilder;
Mason Tang2bebde72010-08-04 17:20:24 -070063import android.text.TextUtils;
Mason Tang2bebde72010-08-04 17:20:24 -070064import android.text.format.Time;
Andy McFadden73b07652011-08-23 15:45:09 -070065import android.text.method.LinkMovementMethod;
66import android.text.method.MovementMethod;
Michael Chan8ce3b7d2010-09-01 15:41:01 -070067import android.text.style.ForegroundColorSpan;
Mason Tang2bebde72010-08-04 17:20:24 -070068import android.text.util.Rfc822Token;
69import android.util.Log;
James Kung4afba182012-12-18 23:12:08 -080070import android.util.SparseIntArray;
Michael Chan71d08832010-08-25 18:28:59 -070071import android.view.Gravity;
Mason Tang2bebde72010-08-04 17:20:24 -070072import android.view.LayoutInflater;
Isaac Katzenelson60f01c22011-06-03 15:42:01 -070073import android.view.Menu;
74import android.view.MenuInflater;
75import android.view.MenuItem;
Mason Tang2bebde72010-08-04 17:20:24 -070076import android.view.MotionEvent;
77import android.view.View;
Erikcb811892010-09-28 13:44:19 -070078import android.view.View.OnClickListener;
79import android.view.View.OnTouchListener;
Mason Tang2bebde72010-08-04 17:20:24 -070080import android.view.ViewGroup;
Michael Chan71d08832010-08-25 18:28:59 -070081import android.view.Window;
82import android.view.WindowManager;
Erik259b8f92011-01-12 14:01:12 -080083import android.view.accessibility.AccessibilityEvent;
84import android.view.accessibility.AccessibilityManager;
Mason Tang2bebde72010-08-04 17:20:24 -070085import android.widget.AdapterView;
RoboErik8b5743c2011-09-27 16:07:09 -070086import android.widget.AdapterView.OnItemSelectedListener;
Michael Chan8ce3b7d2010-09-01 15:41:01 -070087import android.widget.Button;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -070088import android.widget.LinearLayout;
Erik259b8f92011-01-12 14:01:12 -080089import android.widget.RadioButton;
Michael Chanf92f46b2010-10-27 18:59:05 -070090import android.widget.RadioGroup;
91import android.widget.RadioGroup.OnCheckedChangeListener;
RoboErik8b5743c2011-09-27 16:07:09 -070092import android.widget.ScrollView;
Mason Tang2bebde72010-08-04 17:20:24 -070093import android.widget.TextView;
94import android.widget.Toast;
95
Michael Chan2c8485c2012-05-09 10:23:45 -070096import com.android.calendar.CalendarController.EventInfo;
97import com.android.calendar.CalendarController.EventType;
98import com.android.calendar.CalendarEventModel.Attendee;
99import com.android.calendar.CalendarEventModel.ReminderEntry;
Sara Ting7da27672012-07-24 16:23:53 -0700100import com.android.calendar.alerts.QuickResponseActivity;
Michael Chan2c8485c2012-05-09 10:23:45 -0700101import com.android.calendar.event.AttendeesView;
102import com.android.calendar.event.EditEventActivity;
103import com.android.calendar.event.EditEventHelper;
James Kung4afba182012-12-18 23:12:08 -0800104import com.android.calendar.event.EventColorPickerDialog;
Michael Chan2c8485c2012-05-09 10:23:45 -0700105import com.android.calendar.event.EventViewUtils;
Sara Tingda3ee392012-12-10 15:18:26 -0800106import com.android.calendarcommon2.DateException;
107import com.android.calendarcommon2.Duration;
Michael Chan8a528ad2012-06-26 17:44:34 -0700108import com.android.calendarcommon2.EventRecurrence;
James Kunga8b8c0d2013-02-13 17:28:16 -0800109import com.android.colorpicker.ColorPickerSwatch.OnColorSelectedListener;
110import com.android.colorpicker.HsvColorComparator;
Michael Chan2c8485c2012-05-09 10:23:45 -0700111
Mason Tang2bebde72010-08-04 17:20:24 -0700112import java.util.ArrayList;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700113import java.util.Arrays;
114import java.util.Collections;
Erik259b8f92011-01-12 14:01:12 -0800115import java.util.List;
Isaac Katzenelsonf6f79772011-06-02 16:29:18 -0700116
Michael Chanf92f46b2010-10-27 18:59:05 -0700117public class EventInfoFragment extends DialogFragment implements OnCheckedChangeListener,
James Kungb8904fb2013-02-14 14:37:42 -0800118 CalendarController.EventHandler, OnClickListener, DeleteEventHelper.DeleteNotifyListener,
119 OnColorSelectedListener {
Michael Chan83efa2d2012-04-24 17:42:21 -0700120
James Kunge134cd52013-02-13 11:33:49 -0800121 public static final boolean DEBUG = false;
Mason Tang2bebde72010-08-04 17:20:24 -0700122
Michael Chan2c7c8512010-12-10 14:12:57 -0800123 public static final String TAG = "EventInfoFragment";
James Kung2fca0242013-04-02 16:09:50 -0700124 public static final String COLOR_PICKER_DIALOG_TAG = "EventColorPickerDialog";
Mason Tang2bebde72010-08-04 17:20:24 -0700125
James Kungb8904fb2013-02-14 14:37:42 -0800126 private static final int REQUEST_CODE_COLOR_PICKER = 0;
127
Isaac Katzenelson60f01c22011-06-03 15:42:01 -0700128 protected static final String BUNDLE_KEY_EVENT_ID = "key_event_id";
129 protected static final String BUNDLE_KEY_START_MILLIS = "key_start_millis";
130 protected static final String BUNDLE_KEY_END_MILLIS = "key_end_millis";
131 protected static final String BUNDLE_KEY_IS_DIALOG = "key_fragment_is_dialog";
Isaac Katzenelsonb0a313a2011-10-24 11:41:56 -0700132 protected static final String BUNDLE_KEY_DELETE_DIALOG_VISIBLE = "key_delete_dialog_visible";
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700133 protected static final String BUNDLE_KEY_WINDOW_STYLE = "key_window_style";
James Kung4afba182012-12-18 23:12:08 -0800134 protected static final String BUNDLE_KEY_CALENDAR_COLOR = "key_calendar_color";
James Kungf56b1492013-03-07 15:10:13 -0800135 protected static final String BUNDLE_KEY_CALENDAR_COLOR_INIT = "key_calendar_color_init";
James Kung4afba182012-12-18 23:12:08 -0800136 protected static final String BUNDLE_KEY_CURRENT_COLOR = "key_current_color";
James Kung497a6252013-05-17 14:47:33 -0700137 protected static final String BUNDLE_KEY_CURRENT_COLOR_KEY = "key_current_color_key";
James Kungf56b1492013-03-07 15:10:13 -0800138 protected static final String BUNDLE_KEY_CURRENT_COLOR_INIT = "key_current_color_init";
James Kung4afba182012-12-18 23:12:08 -0800139 protected static final String BUNDLE_KEY_ORIGINAL_COLOR = "key_original_color";
James Kungf56b1492013-03-07 15:10:13 -0800140 protected static final String BUNDLE_KEY_ORIGINAL_COLOR_INIT = "key_original_color_init";
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -0800141 protected static final String BUNDLE_KEY_ATTENDEE_RESPONSE = "key_attendee_response";
142 protected static final String BUNDLE_KEY_USER_SET_ATTENDEE_RESPONSE =
143 "key_user_set_attendee_response";
144 protected static final String BUNDLE_KEY_TENTATIVE_USER_RESPONSE =
145 "key_tentative_user_response";
146 protected static final String BUNDLE_KEY_RESPONSE_WHICH_EVENTS = "key_response_which_events";
147 protected static final String BUNDLE_KEY_REMINDER_MINUTES = "key_reminder_minutes";
148 protected static final String BUNDLE_KEY_REMINDER_METHODS = "key_reminder_methods";
149
James Kung4afba182012-12-18 23:12:08 -0800150
Erik259b8f92011-01-12 14:01:12 -0800151 private static final String PERIOD_SPACE = ". ";
152
James Kung4afba182012-12-18 23:12:08 -0800153 private static final String NO_EVENT_COLOR = "";
154
Mason Tang2bebde72010-08-04 17:20:24 -0700155 /**
156 * These are the corresponding indices into the array of strings
157 * "R.array.change_response_labels" in the resource file.
158 */
159 static final int UPDATE_SINGLE = 0;
160 static final int UPDATE_ALL = 1;
161
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700162 // Style of view
163 public static final int FULL_WINDOW_STYLE = 0;
164 public static final int DIALOG_WINDOW_STYLE = 1;
165
166 private int mWindowStyle = DIALOG_WINDOW_STYLE;
167
Mason Tang2bebde72010-08-04 17:20:24 -0700168 // Query tokens for QueryHandler
Erik259b8f92011-01-12 14:01:12 -0800169 private static final int TOKEN_QUERY_EVENT = 1 << 0;
170 private static final int TOKEN_QUERY_CALENDARS = 1 << 1;
171 private static final int TOKEN_QUERY_ATTENDEES = 1 << 2;
172 private static final int TOKEN_QUERY_DUPLICATE_CALENDARS = 1 << 3;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700173 private static final int TOKEN_QUERY_REMINDERS = 1 << 4;
Sara Ting6aad0ff2012-08-02 10:55:52 -0700174 private static final int TOKEN_QUERY_VISIBLE_CALENDARS = 1 << 5;
James Kung4afba182012-12-18 23:12:08 -0800175 private static final int TOKEN_QUERY_COLORS = 1 << 6;
176
Erik259b8f92011-01-12 14:01:12 -0800177 private static final int TOKEN_QUERY_ALL = TOKEN_QUERY_DUPLICATE_CALENDARS
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700178 | TOKEN_QUERY_ATTENDEES | TOKEN_QUERY_CALENDARS | TOKEN_QUERY_EVENT
James Kung4afba182012-12-18 23:12:08 -0800179 | TOKEN_QUERY_REMINDERS | TOKEN_QUERY_VISIBLE_CALENDARS | TOKEN_QUERY_COLORS;
Sara Ting6aad0ff2012-08-02 10:55:52 -0700180
Erik259b8f92011-01-12 14:01:12 -0800181 private int mCurrentQuery = 0;
Mason Tang2bebde72010-08-04 17:20:24 -0700182
183 private static final String[] EVENT_PROJECTION = new String[] {
184 Events._ID, // 0 do not remove; used in DeleteEventHelper
185 Events.TITLE, // 1 do not remove; used in DeleteEventHelper
186 Events.RRULE, // 2 do not remove; used in DeleteEventHelper
187 Events.ALL_DAY, // 3 do not remove; used in DeleteEventHelper
188 Events.CALENDAR_ID, // 4 do not remove; used in DeleteEventHelper
189 Events.DTSTART, // 5 do not remove; used in DeleteEventHelper
190 Events._SYNC_ID, // 6 do not remove; used in DeleteEventHelper
191 Events.EVENT_TIMEZONE, // 7 do not remove; used in DeleteEventHelper
192 Events.DESCRIPTION, // 8
193 Events.EVENT_LOCATION, // 9
Michael Chan693ca602012-05-31 12:24:11 -0700194 Calendars.CALENDAR_ACCESS_LEVEL, // 10
James Kung4afba182012-12-18 23:12:08 -0800195 Events.CALENDAR_COLOR, // 11
196 Events.EVENT_COLOR, // 12
197 Events.HAS_ATTENDEE_DATA, // 13
198 Events.ORGANIZER, // 14
199 Events.HAS_ALARM, // 15
200 Calendars.MAX_REMINDERS, // 16
201 Calendars.ALLOWED_REMINDERS, // 17
202 Events.CUSTOM_APP_PACKAGE, // 18
203 Events.CUSTOM_APP_URI, // 19
Sara Tingda3ee392012-12-10 15:18:26 -0800204 Events.DTEND, // 20
205 Events.DURATION, // 21
James Kung4afba182012-12-18 23:12:08 -0800206 Events.ORIGINAL_SYNC_ID // 22 do not remove; used in DeleteEventHelper
Mason Tang2bebde72010-08-04 17:20:24 -0700207 };
208 private static final int EVENT_INDEX_ID = 0;
209 private static final int EVENT_INDEX_TITLE = 1;
210 private static final int EVENT_INDEX_RRULE = 2;
211 private static final int EVENT_INDEX_ALL_DAY = 3;
212 private static final int EVENT_INDEX_CALENDAR_ID = 4;
Sara Tingda3ee392012-12-10 15:18:26 -0800213 private static final int EVENT_INDEX_DTSTART = 5;
Mason Tang2bebde72010-08-04 17:20:24 -0700214 private static final int EVENT_INDEX_SYNC_ID = 6;
215 private static final int EVENT_INDEX_EVENT_TIMEZONE = 7;
216 private static final int EVENT_INDEX_DESCRIPTION = 8;
217 private static final int EVENT_INDEX_EVENT_LOCATION = 9;
Michael Chan71b221a2010-10-25 17:55:44 -0700218 private static final int EVENT_INDEX_ACCESS_LEVEL = 10;
James Kung4afba182012-12-18 23:12:08 -0800219 private static final int EVENT_INDEX_CALENDAR_COLOR = 11;
220 private static final int EVENT_INDEX_EVENT_COLOR = 12;
221 private static final int EVENT_INDEX_HAS_ATTENDEE_DATA = 13;
222 private static final int EVENT_INDEX_ORGANIZER = 14;
223 private static final int EVENT_INDEX_HAS_ALARM = 15;
224 private static final int EVENT_INDEX_MAX_REMINDERS = 16;
225 private static final int EVENT_INDEX_ALLOWED_REMINDERS = 17;
226 private static final int EVENT_INDEX_CUSTOM_APP_PACKAGE = 18;
227 private static final int EVENT_INDEX_CUSTOM_APP_URI = 19;
Sara Tingda3ee392012-12-10 15:18:26 -0800228 private static final int EVENT_INDEX_DTEND = 20;
229 private static final int EVENT_INDEX_DURATION = 21;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700230
Mason Tang2bebde72010-08-04 17:20:24 -0700231 private static final String[] ATTENDEES_PROJECTION = new String[] {
232 Attendees._ID, // 0
233 Attendees.ATTENDEE_NAME, // 1
234 Attendees.ATTENDEE_EMAIL, // 2
235 Attendees.ATTENDEE_RELATIONSHIP, // 3
236 Attendees.ATTENDEE_STATUS, // 4
Sara Tingddbc0022012-04-26 17:08:46 -0700237 Attendees.ATTENDEE_IDENTITY, // 5
238 Attendees.ATTENDEE_ID_NAMESPACE // 6
Mason Tang2bebde72010-08-04 17:20:24 -0700239 };
240 private static final int ATTENDEES_INDEX_ID = 0;
241 private static final int ATTENDEES_INDEX_NAME = 1;
242 private static final int ATTENDEES_INDEX_EMAIL = 2;
243 private static final int ATTENDEES_INDEX_RELATIONSHIP = 3;
244 private static final int ATTENDEES_INDEX_STATUS = 4;
Sara Tingddbc0022012-04-26 17:08:46 -0700245 private static final int ATTENDEES_INDEX_IDENTITY = 5;
246 private static final int ATTENDEES_INDEX_ID_NAMESPACE = 6;
Mason Tang2bebde72010-08-04 17:20:24 -0700247
Michael Chan693ca602012-05-31 12:24:11 -0700248 static {
Sara Tingfac2d152012-05-31 14:59:57 -0700249 if (!Utils.isJellybeanOrLater()) {
Michael Chan693ca602012-05-31 12:24:11 -0700250 EVENT_PROJECTION[EVENT_INDEX_CUSTOM_APP_PACKAGE] = Events._ID; // dummy value
251 EVENT_PROJECTION[EVENT_INDEX_CUSTOM_APP_URI] = Events._ID; // dummy value
252
253 ATTENDEES_PROJECTION[ATTENDEES_INDEX_IDENTITY] = Attendees._ID; // dummy value
254 ATTENDEES_PROJECTION[ATTENDEES_INDEX_ID_NAMESPACE] = Attendees._ID; // dummy value
255 }
256 }
257
Mason Tang2bebde72010-08-04 17:20:24 -0700258 private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=?";
259
260 private static final String ATTENDEES_SORT_ORDER = Attendees.ATTENDEE_NAME + " ASC, "
261 + Attendees.ATTENDEE_EMAIL + " ASC";
262
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700263 private static final String[] REMINDERS_PROJECTION = new String[] {
264 Reminders._ID, // 0
265 Reminders.MINUTES, // 1
266 Reminders.METHOD // 2
267 };
268 private static final int REMINDERS_INDEX_ID = 0;
269 private static final int REMINDERS_MINUTES_ID = 1;
270 private static final int REMINDERS_METHOD_ID = 2;
271
272 private static final String REMINDERS_WHERE = Reminders.EVENT_ID + "=?";
273
Mason Tang2bebde72010-08-04 17:20:24 -0700274 static final String[] CALENDARS_PROJECTION = new String[] {
275 Calendars._ID, // 0
RoboErikef2add92011-06-09 14:49:53 -0700276 Calendars.CALENDAR_DISPLAY_NAME, // 1
Mason Tang2bebde72010-08-04 17:20:24 -0700277 Calendars.OWNER_ACCOUNT, // 2
Sara Ting42896f72012-03-15 15:24:36 -0700278 Calendars.CAN_ORGANIZER_RESPOND, // 3
James Kung4afba182012-12-18 23:12:08 -0800279 Calendars.ACCOUNT_NAME, // 4
280 Calendars.ACCOUNT_TYPE // 5
Mason Tang2bebde72010-08-04 17:20:24 -0700281 };
282 static final int CALENDARS_INDEX_DISPLAY_NAME = 1;
283 static final int CALENDARS_INDEX_OWNER_ACCOUNT = 2;
284 static final int CALENDARS_INDEX_OWNER_CAN_RESPOND = 3;
Sara Ting42896f72012-03-15 15:24:36 -0700285 static final int CALENDARS_INDEX_ACCOUNT_NAME = 4;
James Kung4afba182012-12-18 23:12:08 -0800286 static final int CALENDARS_INDEX_ACCOUNT_TYPE = 5;
Mason Tang2bebde72010-08-04 17:20:24 -0700287
288 static final String CALENDARS_WHERE = Calendars._ID + "=?";
RoboErikef2add92011-06-09 14:49:53 -0700289 static final String CALENDARS_DUPLICATE_NAME_WHERE = Calendars.CALENDAR_DISPLAY_NAME + "=?";
Sara Ting6aad0ff2012-08-02 10:55:52 -0700290 static final String CALENDARS_VISIBLE_WHERE = Calendars.VISIBLE + "=?";
Mason Tang2bebde72010-08-04 17:20:24 -0700291
James Kung4afba182012-12-18 23:12:08 -0800292 static final String[] COLORS_PROJECTION = new String[] {
293 Colors._ID, // 0
294 Colors.COLOR, // 1
295 Colors.COLOR_KEY // 2
296 };
297
298 static final String COLORS_WHERE = Colors.ACCOUNT_NAME + "=? AND " + Colors.ACCOUNT_TYPE +
299 "=? AND " + Colors.COLOR_TYPE + "=" + Colors.TYPE_EVENT;
300
301 public static final int COLORS_INDEX_COLOR = 1;
302 public static final int COLORS_INDEX_COLOR_KEY = 2;
Andy McFaddenfd8ce5e2011-11-15 15:44:57 -0800303
Mason Tang2bebde72010-08-04 17:20:24 -0700304 private View mView;
Mason Tang2bebde72010-08-04 17:20:24 -0700305
306 private Uri mUri;
307 private long mEventId;
308 private Cursor mEventCursor;
309 private Cursor mAttendeesCursor;
310 private Cursor mCalendarsCursor;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700311 private Cursor mRemindersCursor;
312
Michael Chan0a01fd32011-01-23 15:13:28 -0800313 private static float mScale = 0; // Used for supporting different screen densities
Mason Tang2bebde72010-08-04 17:20:24 -0700314
Michael Chan2c8485c2012-05-09 10:23:45 -0700315 private static int mCustomAppIconSize = 32;
316
Mason Tang2bebde72010-08-04 17:20:24 -0700317 private long mStartMillis;
318 private long mEndMillis;
Michael Chan8b1119b2012-01-06 16:04:55 -0800319 private boolean mAllDay;
Mason Tang2bebde72010-08-04 17:20:24 -0700320
321 private boolean mHasAttendeeData;
Michael Chan83efa2d2012-04-24 17:42:21 -0700322 private String mEventOrganizerEmail;
323 private String mEventOrganizerDisplayName = "";
Mason Tang2bebde72010-08-04 17:20:24 -0700324 private boolean mIsOrganizer;
Erikd845fbe2010-08-12 11:20:01 -0700325 private long mCalendarOwnerAttendeeId = EditEventHelper.ATTENDEE_ID_NONE;
Michael Chan352e1a22010-09-28 05:15:08 -0700326 private boolean mOwnerCanRespond;
Sara Ting42896f72012-03-15 15:24:36 -0700327 private String mSyncAccountName;
Mason Tang2bebde72010-08-04 17:20:24 -0700328 private String mCalendarOwnerAccount;
329 private boolean mCanModifyCalendar;
RoboErik65eeb792011-08-08 12:54:00 -0700330 private boolean mCanModifyEvent;
Mason Tang2bebde72010-08-04 17:20:24 -0700331 private boolean mIsBusyFreeCalendar;
Mason Tang2bebde72010-08-04 17:20:24 -0700332 private int mNumOfAttendees;
Mason Tang2bebde72010-08-04 17:20:24 -0700333 private EditResponseHelper mEditResponseHelper;
Isaac Katzenelsonb0a313a2011-10-24 11:41:56 -0700334 private boolean mDeleteDialogVisible = false;
335 private DeleteEventHelper mDeleteHelper;
Mason Tang2bebde72010-08-04 17:20:24 -0700336
Mason Tang2bebde72010-08-04 17:20:24 -0700337 private int mOriginalAttendeeResponse;
Isaac Katzenelson6bcafcf2012-05-02 18:25:36 -0700338 private int mAttendeeResponseFromIntent = Attendees.ATTENDEE_STATUS_NONE;
339 private int mUserSetResponse = Attendees.ATTENDEE_STATUS_NONE;
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800340 private int mWhichEvents = -1;
341 // Used as the temporary response until the dialog is confirmed. It is also
342 // able to be used as a state marker for configuration changes.
343 private int mTentativeUserSetResponse = Attendees.ATTENDEE_STATUS_NONE;
Mason Tang2bebde72010-08-04 17:20:24 -0700344 private boolean mIsRepeating;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700345 private boolean mHasAlarm;
346 private int mMaxReminders;
347 private String mCalendarAllowedReminders;
Isaac Katzenelsonb33cdf42011-10-14 18:15:18 -0700348 // Used to prevent saving changes in event if it is being deleted.
349 private boolean mEventDeletionStarted = false;
Mason Tang2bebde72010-08-04 17:20:24 -0700350
Erik259b8f92011-01-12 14:01:12 -0800351 private TextView mTitle;
Sara Ting75f53662012-04-09 15:37:10 -0700352 private TextView mWhenDateTime;
Erik259b8f92011-01-12 14:01:12 -0800353 private TextView mWhere;
Michael Chan99704a22011-11-11 10:24:37 -0800354 private ExpandableTextView mDesc;
Isaac Katzenelsonc0624ee2011-06-03 09:24:27 -0700355 private AttendeesView mLongAttendees;
Sara Ting7ffa24c2012-08-28 15:44:37 -0700356 private Button emailAttendeesButton;
RoboErikd8353fb2011-07-21 11:28:11 -0700357 private Menu mMenu = null;
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -0700358 private View mHeadlines;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700359 private ScrollView mScrollView;
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800360 private View mLoadingMsgView;
Paul Sliwowski1aba96a2013-05-20 20:27:12 -0700361 private View mErrorMsgView;
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800362 private ObjectAnimator mAnimateAlpha;
Isaac Katzenelson263b0292012-03-14 14:55:50 -0700363 private long mLoadingMsgStartTime;
James Kung4afba182012-12-18 23:12:08 -0800364
James Kung2fca0242013-04-02 16:09:50 -0700365 private EventColorPickerDialog mColorPickerDialog;
James Kunge134cd52013-02-13 11:33:49 -0800366 private SparseIntArray mDisplayColorKeyMap = new SparseIntArray();
James Kung4afba182012-12-18 23:12:08 -0800367 private int[] mColors;
368 private int mOriginalColor = -1;
James Kungf56b1492013-03-07 15:10:13 -0800369 private boolean mOriginalColorInitialized = false;
James Kung4afba182012-12-18 23:12:08 -0800370 private int mCalendarColor = -1;
James Kungf56b1492013-03-07 15:10:13 -0800371 private boolean mCalendarColorInitialized = false;
James Kung4afba182012-12-18 23:12:08 -0800372 private int mCurrentColor = -1;
James Kungf56b1492013-03-07 15:10:13 -0800373 private boolean mCurrentColorInitialized = false;
James Kung497a6252013-05-17 14:47:33 -0700374 private int mCurrentColorKey = -1;
James Kung4afba182012-12-18 23:12:08 -0800375
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800376 private static final int FADE_IN_TIME = 300; // in milliseconds
Isaac Katzenelson263b0292012-03-14 14:55:50 -0700377 private static final int LOADING_MSG_DELAY = 600; // in milliseconds
378 private static final int LOADING_MSG_MIN_DISPLAY_TIME = 600;
Isaac Katzenelson80d640f2012-04-20 09:21:28 -0700379 private boolean mNoCrossFade = false; // Used to prevent repeated cross-fade
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800380 private RadioGroup mResponseRadioGroup;
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800381
Mason Tang2bebde72010-08-04 17:20:24 -0700382 ArrayList<Attendee> mAcceptedAttendees = new ArrayList<Attendee>();
383 ArrayList<Attendee> mDeclinedAttendees = new ArrayList<Attendee>();
384 ArrayList<Attendee> mTentativeAttendees = new ArrayList<Attendee>();
385 ArrayList<Attendee> mNoResponseAttendees = new ArrayList<Attendee>();
Sara Tingcb5f5682012-04-04 22:52:20 -0700386 ArrayList<String> mToEmails = new ArrayList<String>();
387 ArrayList<String> mCcEmails = new ArrayList<String>();
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700388
389 private int mDefaultReminderMinutes;
Isaac Katzenelsonac4350b2012-04-18 15:33:26 -0700390 private final ArrayList<LinearLayout> mReminderViews = new ArrayList<LinearLayout>(0);
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700391 public ArrayList<ReminderEntry> mReminders;
RoboErik7f078b72011-09-06 10:25:31 -0700392 public ArrayList<ReminderEntry> mOriginalReminders = new ArrayList<ReminderEntry>();
393 public ArrayList<ReminderEntry> mUnsupportedReminders = new ArrayList<ReminderEntry>();
RoboErik8b5743c2011-09-27 16:07:09 -0700394 private boolean mUserModifiedReminders = false;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700395
396 /**
397 * Contents of the "minutes" spinner. This has default values from the XML file, augmented
398 * with any additional values that were already associated with the event.
399 */
400 private ArrayList<Integer> mReminderMinuteValues;
401 private ArrayList<String> mReminderMinuteLabels;
402
403 /**
404 * Contents of the "methods" spinner. The "values" list specifies the method constant
405 * (e.g. {@link Reminders#METHOD_ALERT}) associated with the labels. Any methods that
406 * aren't allowed by the Calendar will be removed.
407 */
408 private ArrayList<Integer> mReminderMethodValues;
409 private ArrayList<String> mReminderMethodLabels;
410
Mason Tang2bebde72010-08-04 17:20:24 -0700411 private QueryHandler mHandler;
412
Isaac Katzenelsonb33cdf42011-10-14 18:15:18 -0700413
Isaac Katzenelsonac4350b2012-04-18 15:33:26 -0700414 private final Runnable mTZUpdater = new Runnable() {
Erikcb811892010-09-28 13:44:19 -0700415 @Override
416 public void run() {
417 updateEvent(mView);
418 }
419 };
420
Isaac Katzenelsonac4350b2012-04-18 15:33:26 -0700421 private final Runnable mLoadingMsgAlphaUpdater = new Runnable() {
Isaac Katzenelson263b0292012-03-14 14:55:50 -0700422 @Override
423 public void run() {
424 // Since this is run after a delay, make sure to only show the message
425 // if the event's data is not shown yet.
426 if (!mAnimateAlpha.isRunning() && mScrollView.getAlpha() == 0) {
427 mLoadingMsgStartTime = System.currentTimeMillis();
428 mLoadingMsgView.setAlpha(1);
429 }
430 }
431 };
432
RoboErik8b5743c2011-09-27 16:07:09 -0700433 private OnItemSelectedListener mReminderChangeListener;
434
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700435 private static int mDialogWidth = 500;
436 private static int mDialogHeight = 600;
Isaac Katzenelson0aa0c612011-10-03 16:46:10 -0700437 private static int DIALOG_TOP_MARGIN = 8;
Michael Chan71d08832010-08-25 18:28:59 -0700438 private boolean mIsDialog = false;
RoboErik7c6236d2011-02-24 16:41:18 -0800439 private boolean mIsPaused = true;
440 private boolean mDismissOnResume = false;
Michael Chan71d08832010-08-25 18:28:59 -0700441 private int mX = -1;
442 private int mY = -1;
Isaac Katzenelson0aa0c612011-10-03 16:46:10 -0700443 private int mMinTop; // Dialog cannot be above this location
Isaac Katzenelson10b60212011-06-28 17:59:14 -0700444 private boolean mIsTabletConfig;
445 private Activity mActivity;
Michael Chanbe2a4322011-08-11 13:39:14 -0700446 private Context mContext;
Michael Chan71d08832010-08-25 18:28:59 -0700447
James Kung4afba182012-12-18 23:12:08 -0800448 private CalendarController mController;
449
Mason Tang2bebde72010-08-04 17:20:24 -0700450 private class QueryHandler extends AsyncQueryService {
451 public QueryHandler(Context context) {
452 super(context);
453 }
454
455 @Override
456 protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
Mason Tang4003d1c2010-08-17 13:50:45 -0700457 // if the activity is finishing, then close the cursor and return
458 final Activity activity = getActivity();
459 if (activity == null || activity.isFinishing()) {
Isaac Katzenelson47f6cc62012-06-28 18:56:16 -0700460 if (cursor != null) {
461 cursor.close();
462 }
Mason Tang4003d1c2010-08-17 13:50:45 -0700463 return;
464 }
465
Mason Tang2bebde72010-08-04 17:20:24 -0700466 switch (token) {
467 case TOKEN_QUERY_EVENT:
468 mEventCursor = Utils.matrixCursorFromCursor(cursor);
Paul Sliwowski1aba96a2013-05-20 20:27:12 -0700469 if (!initEventCursor()) {
470 displayEventNotFound();
Mason Tang2bebde72010-08-04 17:20:24 -0700471 return;
472 }
James Kungf56b1492013-03-07 15:10:13 -0800473 if (!mCalendarColorInitialized) {
James Kung4afba182012-12-18 23:12:08 -0800474 mCalendarColor = Utils.getDisplayColorFromColor(
475 mEventCursor.getInt(EVENT_INDEX_CALENDAR_COLOR));
James Kungf56b1492013-03-07 15:10:13 -0800476 mCalendarColorInitialized = true;
James Kung4afba182012-12-18 23:12:08 -0800477 }
478
James Kungf56b1492013-03-07 15:10:13 -0800479 if (!mOriginalColorInitialized) {
James Kung4afba182012-12-18 23:12:08 -0800480 mOriginalColor = mEventCursor.isNull(EVENT_INDEX_EVENT_COLOR)
481 ? mCalendarColor : Utils.getDisplayColorFromColor(
482 mEventCursor.getInt(EVENT_INDEX_EVENT_COLOR));
James Kungf56b1492013-03-07 15:10:13 -0800483 mOriginalColorInitialized = true;
James Kung4afba182012-12-18 23:12:08 -0800484 }
485
James Kungf56b1492013-03-07 15:10:13 -0800486 if (!mCurrentColorInitialized) {
James Kung4afba182012-12-18 23:12:08 -0800487 mCurrentColor = mOriginalColor;
James Kungf56b1492013-03-07 15:10:13 -0800488 mCurrentColorInitialized = true;
James Kung4afba182012-12-18 23:12:08 -0800489 }
490
Mason Tang2bebde72010-08-04 17:20:24 -0700491 updateEvent(mView);
RoboErike35a0322011-09-01 16:21:49 -0700492 prepareReminders();
Mason Tang2bebde72010-08-04 17:20:24 -0700493
494 // start calendar query
495 Uri uri = Calendars.CONTENT_URI;
496 String[] args = new String[] {
497 Long.toString(mEventCursor.getLong(EVENT_INDEX_CALENDAR_ID))};
498 startQuery(TOKEN_QUERY_CALENDARS, null, uri, CALENDARS_PROJECTION,
499 CALENDARS_WHERE, args, null);
500 break;
501 case TOKEN_QUERY_CALENDARS:
502 mCalendarsCursor = Utils.matrixCursorFromCursor(cursor);
503 updateCalendar(mView);
Mason Tang4003d1c2010-08-17 13:50:45 -0700504 // FRAG_TODO fragments shouldn't set the title anymore
Mason Tang2bebde72010-08-04 17:20:24 -0700505 updateTitle();
506
James Kung4afba182012-12-18 23:12:08 -0800507 args = new String[] {
508 mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_NAME),
509 mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_TYPE) };
510 uri = Colors.CONTENT_URI;
511 startQuery(TOKEN_QUERY_COLORS, null, uri, COLORS_PROJECTION, COLORS_WHERE, args,
512 null);
513
Michael Chan352e1a22010-09-28 05:15:08 -0700514 if (!mIsBusyFreeCalendar) {
Michael Chan352e1a22010-09-28 05:15:08 -0700515 args = new String[] { Long.toString(mEventId) };
Mason Tang2bebde72010-08-04 17:20:24 -0700516
Michael Chan352e1a22010-09-28 05:15:08 -0700517 // start attendees query
518 uri = Attendees.CONTENT_URI;
519 startQuery(TOKEN_QUERY_ATTENDEES, null, uri, ATTENDEES_PROJECTION,
520 ATTENDEES_WHERE, args, ATTENDEES_SORT_ORDER);
Erik259b8f92011-01-12 14:01:12 -0800521 } else {
522 sendAccessibilityEventIfQueryDone(TOKEN_QUERY_ATTENDEES);
Mason Tang2bebde72010-08-04 17:20:24 -0700523 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700524 if (mHasAlarm) {
525 // start reminders query
526 args = new String[] { Long.toString(mEventId) };
527 uri = Reminders.CONTENT_URI;
528 startQuery(TOKEN_QUERY_REMINDERS, null, uri,
529 REMINDERS_PROJECTION, REMINDERS_WHERE, args, null);
530 } else {
531 sendAccessibilityEventIfQueryDone(TOKEN_QUERY_REMINDERS);
532 }
Mason Tang2bebde72010-08-04 17:20:24 -0700533 break;
James Kung4afba182012-12-18 23:12:08 -0800534 case TOKEN_QUERY_COLORS:
535 ArrayList<Integer> colors = new ArrayList<Integer>();
536 if (cursor.moveToFirst()) {
537 do
538 {
539 int colorKey = cursor.getInt(COLORS_INDEX_COLOR_KEY);
540 int rawColor = cursor.getInt(COLORS_INDEX_COLOR);
541 int displayColor = Utils.getDisplayColorFromColor(rawColor);
James Kunge134cd52013-02-13 11:33:49 -0800542 mDisplayColorKeyMap.put(displayColor, colorKey);
James Kung4afba182012-12-18 23:12:08 -0800543 colors.add(displayColor);
544 } while (cursor.moveToNext());
545 }
546 cursor.close();
547 Integer[] sortedColors = new Integer[colors.size()];
James Kunge134cd52013-02-13 11:33:49 -0800548 Arrays.sort(colors.toArray(sortedColors), new HsvColorComparator());
James Kung4afba182012-12-18 23:12:08 -0800549 mColors = new int[sortedColors.length];
550 for (int i = 0; i < sortedColors.length; i++) {
551 mColors[i] = sortedColors[i].intValue();
552
553 float[] hsv = new float[3];
554 Color.colorToHSV(mColors[i], hsv);
James Kunge134cd52013-02-13 11:33:49 -0800555 if (DEBUG) {
556 Log.d("Color", "H:" + hsv[0] + ",S:" + hsv[1] + ",V:" + hsv[2]);
557 }
James Kung4afba182012-12-18 23:12:08 -0800558 }
James Kung6090ba22013-04-03 13:00:49 -0700559 if (mCanModifyCalendar) {
560 View button = mView.findViewById(R.id.change_color);
561 if (button != null && mColors.length > 0) {
562 button.setEnabled(true);
563 button.setVisibility(View.VISIBLE);
564 }
James Kung4afba182012-12-18 23:12:08 -0800565 }
566 updateMenu();
James Kung4afba182012-12-18 23:12:08 -0800567 break;
Mason Tang2bebde72010-08-04 17:20:24 -0700568 case TOKEN_QUERY_ATTENDEES:
569 mAttendeesCursor = Utils.matrixCursorFromCursor(cursor);
570 initAttendeesCursor(mView);
571 updateResponse(mView);
572 break;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700573 case TOKEN_QUERY_REMINDERS:
574 mRemindersCursor = Utils.matrixCursorFromCursor(cursor);
575 initReminders(mView, mRemindersCursor);
576 break;
Sara Ting6aad0ff2012-08-02 10:55:52 -0700577 case TOKEN_QUERY_VISIBLE_CALENDARS:
578 if (cursor.getCount() > 1) {
579 // Start duplicate calendars query to detect whether to add the calendar
580 // email to the calendar owner display.
581 String displayName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
582 mHandler.startQuery(TOKEN_QUERY_DUPLICATE_CALENDARS, null,
583 Calendars.CONTENT_URI, CALENDARS_PROJECTION,
584 CALENDARS_DUPLICATE_NAME_WHERE, new String[] {displayName}, null);
585 } else {
586 // Don't need to display the calendar owner when there is only a single
587 // calendar. Skip the duplicate calendars query.
588 setVisibilityCommon(mView, R.id.calendar_container, View.GONE);
589 mCurrentQuery |= TOKEN_QUERY_DUPLICATE_CALENDARS;
590 }
591 break;
Mason Tang2bebde72010-08-04 17:20:24 -0700592 case TOKEN_QUERY_DUPLICATE_CALENDARS:
Michael Chan71b221a2010-10-25 17:55:44 -0700593 SpannableStringBuilder sb = new SpannableStringBuilder();
594
Michael Chan71b221a2010-10-25 17:55:44 -0700595 // Calendar display name
Mason Tang2bebde72010-08-04 17:20:24 -0700596 String calendarName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
Michael Chan71b221a2010-10-25 17:55:44 -0700597 sb.append(calendarName);
598
599 // Show email account if display name is not unique and
600 // display name != email
601 String email = mCalendarsCursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
Sara Ting6aad0ff2012-08-02 10:55:52 -0700602 if (cursor.getCount() > 1 && !calendarName.equalsIgnoreCase(email) &&
603 Utils.isValidEmail(email)) {
Michael Chan71b221a2010-10-25 17:55:44 -0700604 sb.append(" (").append(email).append(")");
605 }
606
Sara Ting6aad0ff2012-08-02 10:55:52 -0700607 setVisibilityCommon(mView, R.id.calendar_container, View.VISIBLE);
608 setTextCommon(mView, R.id.calendar_name, sb);
Mason Tang2bebde72010-08-04 17:20:24 -0700609 break;
610 }
611 cursor.close();
Erik259b8f92011-01-12 14:01:12 -0800612 sendAccessibilityEventIfQueryDone(token);
Sara Ting6aad0ff2012-08-02 10:55:52 -0700613
614 // All queries are done, show the view.
Isaac Katzenelson263b0292012-03-14 14:55:50 -0700615 if (mCurrentQuery == TOKEN_QUERY_ALL) {
616 if (mLoadingMsgView.getAlpha() == 1) {
617 // Loading message is showing, let it stay a bit more (to prevent
618 // flashing) by adding a start delay to the event animation
619 long timeDiff = LOADING_MSG_MIN_DISPLAY_TIME - (System.currentTimeMillis() -
620 mLoadingMsgStartTime);
621 if (timeDiff > 0) {
622 mAnimateAlpha.setStartDelay(timeDiff);
623 }
624 }
Isaac Katzenelson80d640f2012-04-20 09:21:28 -0700625 if (!mAnimateAlpha.isRunning() &&!mAnimateAlpha.isStarted() && !mNoCrossFade) {
626 mAnimateAlpha.start();
627 } else {
628 mScrollView.setAlpha(1);
629 mLoadingMsgView.setVisibility(View.GONE);
630 }
Isaac Katzenelson263b0292012-03-14 14:55:50 -0700631 }
Mason Tang2bebde72010-08-04 17:20:24 -0700632 }
Mason Tang2bebde72010-08-04 17:20:24 -0700633 }
634
Erik259b8f92011-01-12 14:01:12 -0800635 private void sendAccessibilityEventIfQueryDone(int token) {
636 mCurrentQuery |= token;
637 if (mCurrentQuery == TOKEN_QUERY_ALL) {
638 sendAccessibilityEvent();
639 }
640 }
641
Michael Chan0a01fd32011-01-23 15:13:28 -0800642 public EventInfoFragment(Context context, Uri uri, long startMillis, long endMillis,
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -0800643 int attendeeResponse, boolean isDialog, int windowStyle,
644 ArrayList<ReminderEntry> reminders) {
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700645
Michael Chan2c8485c2012-05-09 10:23:45 -0700646 Resources r = context.getResources();
647 if (mScale == 0) {
648 mScale = context.getResources().getDisplayMetrics().density;
649 if (mScale != 1) {
650 mCustomAppIconSize *= mScale;
651 if (isDialog) {
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700652 DIALOG_TOP_MARGIN *= mScale;
653 }
Michael Chan0a01fd32011-01-23 15:13:28 -0800654 }
655 }
Michael Chan363aa9c2012-05-17 10:31:32 -0700656 if (isDialog) {
657 setDialogSize(r);
658 }
Isaac Katzenelson60f01c22011-06-03 15:42:01 -0700659 mIsDialog = isDialog;
Isaac Katzenelsonc0624ee2011-06-03 09:24:27 -0700660
Michael Chan2fc6b792011-01-26 17:12:44 -0800661 setStyle(DialogFragment.STYLE_NO_TITLE, 0);
Mason Tang2bebde72010-08-04 17:20:24 -0700662 mUri = uri;
663 mStartMillis = startMillis;
664 mEndMillis = endMillis;
665 mAttendeeResponseFromIntent = attendeeResponse;
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700666 mWindowStyle = windowStyle;
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -0800667
668 // Pass in null if no reminders are being specified.
669 // This may be used to explicitly show certain reminders already known
670 // about, such as during configuration changes.
671 mReminders = reminders;
Mason Tang2bebde72010-08-04 17:20:24 -0700672 }
673
Andy McFaddenef31a982011-06-09 07:38:56 -0700674 // This is currently required by the fragment manager.
Isaac Katzenelson60f01c22011-06-03 15:42:01 -0700675 public EventInfoFragment() {
676 }
677
Michael Chan0a01fd32011-01-23 15:13:28 -0800678 public EventInfoFragment(Context context, long eventId, long startMillis, long endMillis,
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -0800679 int attendeeResponse, boolean isDialog, int windowStyle,
680 ArrayList<ReminderEntry> reminders) {
Michael Chan0a01fd32011-01-23 15:13:28 -0800681 this(context, ContentUris.withAppendedId(Events.CONTENT_URI, eventId), startMillis,
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -0800682 endMillis, attendeeResponse, isDialog, windowStyle, reminders);
Mason Tang4003d1c2010-08-17 13:50:45 -0700683 mEventId = eventId;
684 }
685
Michael Chan71d08832010-08-25 18:28:59 -0700686 @Override
687 public void onActivityCreated(Bundle savedInstanceState) {
688 super.onActivityCreated(savedInstanceState);
689
RoboErik8b5743c2011-09-27 16:07:09 -0700690 mReminderChangeListener = new OnItemSelectedListener() {
691 @Override
692 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
693 Integer prevValue = (Integer) parent.getTag();
694 if (prevValue == null || prevValue != position) {
695 parent.setTag(position);
696 mUserModifiedReminders = true;
697 }
698 }
699
700 @Override
701 public void onNothingSelected(AdapterView<?> parent) {
702 // do nothing
703 }
704
705 };
706
Michael Chan71d08832010-08-25 18:28:59 -0700707 if (savedInstanceState != null) {
708 mIsDialog = savedInstanceState.getBoolean(BUNDLE_KEY_IS_DIALOG, false);
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700709 mWindowStyle = savedInstanceState.getInt(BUNDLE_KEY_WINDOW_STYLE,
710 DIALOG_WINDOW_STYLE);
Michael Chan71d08832010-08-25 18:28:59 -0700711 }
712
713 if (mIsDialog) {
714 applyDialogParams();
715 }
James Kung2fca0242013-04-02 16:09:50 -0700716
717 final Activity activity = getActivity();
718 mContext = activity;
719 mColorPickerDialog = (EventColorPickerDialog) activity.getFragmentManager()
720 .findFragmentByTag(COLOR_PICKER_DIALOG_TAG);
721 if (mColorPickerDialog != null) {
722 mColorPickerDialog.setOnColorSelectedListener(this);
723 }
Michael Chan71d08832010-08-25 18:28:59 -0700724 }
725
726 private void applyDialogParams() {
727 Dialog dialog = getDialog();
728 dialog.setCanceledOnTouchOutside(true);
729
730 Window window = dialog.getWindow();
731 window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
732
733 WindowManager.LayoutParams a = window.getAttributes();
734 a.dimAmount = .4f;
735
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700736 a.width = mDialogWidth;
737 a.height = mDialogHeight;
Michael Chan71d08832010-08-25 18:28:59 -0700738
Michael Chan71d08832010-08-25 18:28:59 -0700739
Isaac Katzenelson0b1bd102011-04-07 14:26:29 -0700740 // On tablets , do smart positioning of dialog
741 // On phones , use the whole screen
742
Isaac Katzenelson60f01c22011-06-03 15:42:01 -0700743 if (mX != -1 || mY != -1) {
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700744 a.x = mX - mDialogWidth / 2;
745 a.y = mY - mDialogHeight / 2;
Isaac Katzenelson0aa0c612011-10-03 16:46:10 -0700746 if (a.y < mMinTop) {
747 a.y = mMinTop + DIALOG_TOP_MARGIN;
Isaac Katzenelson0b1bd102011-04-07 14:26:29 -0700748 }
Isaac Katzenelson60f01c22011-06-03 15:42:01 -0700749 a.gravity = Gravity.LEFT | Gravity.TOP;
Isaac Katzenelson0b1bd102011-04-07 14:26:29 -0700750 }
Michael Chan71d08832010-08-25 18:28:59 -0700751 window.setAttributes(a);
752 }
753
Isaac Katzenelson0aa0c612011-10-03 16:46:10 -0700754 public void setDialogParams(int x, int y, int minTop) {
Michael Chan71d08832010-08-25 18:28:59 -0700755 mX = x;
756 mY = y;
Isaac Katzenelson0aa0c612011-10-03 16:46:10 -0700757 mMinTop = minTop;
Michael Chan71d08832010-08-25 18:28:59 -0700758 }
759
Michael Chanf92f46b2010-10-27 18:59:05 -0700760 // Implements OnCheckedChangeListener
761 @Override
762 public void onCheckedChanged(RadioGroup group, int checkedId) {
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800763 // If we haven't finished the return from the dialog yet, don't display.
764 if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
765 return;
766 }
767
Mason Tang2bebde72010-08-04 17:20:24 -0700768 // If this is not a repeating event, then don't display the dialog
769 // asking which events to change.
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800770 int response = getResponseFromButtonId(checkedId);
Mason Tang2bebde72010-08-04 17:20:24 -0700771 if (!mIsRepeating) {
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800772 mUserSetResponse = response;
Mason Tang2bebde72010-08-04 17:20:24 -0700773 return;
774 }
775
776 // If the selection is the same as the original, then don't display the
777 // dialog asking which events to change.
Michael Chanf92f46b2010-10-27 18:59:05 -0700778 if (checkedId == findButtonIdForResponse(mOriginalAttendeeResponse)) {
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800779 mUserSetResponse = response;
Mason Tang2bebde72010-08-04 17:20:24 -0700780 return;
781 }
782
783 // This is a repeating event. We need to ask the user if they mean to
784 // change just this one instance or all instances.
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800785 mTentativeUserSetResponse = response;
786 mEditResponseHelper.showDialog(mWhichEvents);
Mason Tang2bebde72010-08-04 17:20:24 -0700787 }
788
789 public void onNothingSelected(AdapterView<?> parent) {
790 }
791
792 @Override
James Kung4afba182012-12-18 23:12:08 -0800793 public void onDetach() {
794 super.onDetach();
795 mController.deregisterEventHandler(R.layout.event_info);
796 }
797
798 @Override
Mason Tang2bebde72010-08-04 17:20:24 -0700799 public void onAttach(Activity activity) {
800 super.onAttach(activity);
Isaac Katzenelson10b60212011-06-28 17:59:14 -0700801 mActivity = activity;
James Kung1dadfa22013-04-11 19:22:41 -0700802 // Ensure that mIsTabletConfig is set before creating the menu.
James Kung00544122013-04-15 12:15:22 -0700803 mIsTabletConfig = Utils.getConfigBool(mActivity, R.bool.tablet_config);
James Kung4afba182012-12-18 23:12:08 -0800804 mController = CalendarController.getInstance(mActivity);
805 mController.registerEventHandler(R.layout.event_info, this);
Mason Tang2bebde72010-08-04 17:20:24 -0700806 mEditResponseHelper = new EditResponseHelper(activity);
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800807 mEditResponseHelper.setDismissListener(
808 new DialogInterface.OnDismissListener() {
809 @Override
810 public void onDismiss(DialogInterface dialog) {
811 // If the user dismisses the dialog (without hitting OK),
812 // then we want to revert the selection that opened the dialog.
813 if (mEditResponseHelper.getWhichEvents() != -1) {
814 mUserSetResponse = mTentativeUserSetResponse;
815 mWhichEvents = mEditResponseHelper.getWhichEvents();
816 } else {
817 // Revert the attending response radio selection to whatever
818 // was selected prior to this selection (possibly nothing).
819 int oldResponse;
820 if (mUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
821 oldResponse = mUserSetResponse;
822 } else {
823 oldResponse = mOriginalAttendeeResponse;
824 }
825 int buttonToCheck = findButtonIdForResponse(oldResponse);
826
827 if (mResponseRadioGroup != null) {
828 mResponseRadioGroup.check(buttonToCheck);
829 }
830
831 // If the radio group is being cleared, also clear the
832 // dialog's selection of which events should be included
833 // in this response.
834 if (buttonToCheck == -1) {
835 mEditResponseHelper.setWhichEvents(-1);
836 }
837 }
838
839 // Since OnPause will force the dialog to dismiss, do
840 // not change the dialog status
841 if (!mIsPaused) {
842 mTentativeUserSetResponse = Attendees.ATTENDEE_STATUS_NONE;
843 }
844 }
845 });
RoboErik86550ce2011-08-22 16:47:51 -0700846
847 if (mAttendeeResponseFromIntent != Attendees.ATTENDEE_STATUS_NONE) {
848 mEditResponseHelper.setWhichEvents(UPDATE_ALL);
James Kung96267162013-05-01 11:42:57 -0700849 mWhichEvents = mEditResponseHelper.getWhichEvents();
RoboErik86550ce2011-08-22 16:47:51 -0700850 }
Mason Tang2bebde72010-08-04 17:20:24 -0700851 mHandler = new QueryHandler(activity);
Isaac Katzenelson60f01c22011-06-03 15:42:01 -0700852 if (!mIsDialog) {
853 setHasOptionsMenu(true);
854 }
Mason Tang2bebde72010-08-04 17:20:24 -0700855 }
856
857 @Override
858 public View onCreateView(LayoutInflater inflater, ViewGroup container,
859 Bundle savedInstanceState) {
Isaac Katzenelson320c1b12011-11-07 15:31:45 -0800860
861 if (savedInstanceState != null) {
862 mIsDialog = savedInstanceState.getBoolean(BUNDLE_KEY_IS_DIALOG, false);
863 mWindowStyle = savedInstanceState.getInt(BUNDLE_KEY_WINDOW_STYLE,
864 DIALOG_WINDOW_STYLE);
865 mDeleteDialogVisible =
866 savedInstanceState.getBoolean(BUNDLE_KEY_DELETE_DIALOG_VISIBLE,false);
James Kung4afba182012-12-18 23:12:08 -0800867 mCalendarColor = savedInstanceState.getInt(BUNDLE_KEY_CALENDAR_COLOR);
James Kungf56b1492013-03-07 15:10:13 -0800868 mCalendarColorInitialized =
869 savedInstanceState.getBoolean(BUNDLE_KEY_CALENDAR_COLOR_INIT);
James Kung4afba182012-12-18 23:12:08 -0800870 mOriginalColor = savedInstanceState.getInt(BUNDLE_KEY_ORIGINAL_COLOR);
James Kungf56b1492013-03-07 15:10:13 -0800871 mOriginalColorInitialized = savedInstanceState.getBoolean(
872 BUNDLE_KEY_ORIGINAL_COLOR_INIT);
James Kung4afba182012-12-18 23:12:08 -0800873 mCurrentColor = savedInstanceState.getInt(BUNDLE_KEY_CURRENT_COLOR);
James Kungf56b1492013-03-07 15:10:13 -0800874 mCurrentColorInitialized = savedInstanceState.getBoolean(
875 BUNDLE_KEY_CURRENT_COLOR_INIT);
James Kung497a6252013-05-17 14:47:33 -0700876 mCurrentColorKey = savedInstanceState.getInt(BUNDLE_KEY_CURRENT_COLOR_KEY);
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -0800877
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800878 mTentativeUserSetResponse = savedInstanceState.getInt(
879 BUNDLE_KEY_TENTATIVE_USER_RESPONSE,
880 Attendees.ATTENDEE_STATUS_NONE);
881 if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE &&
882 mEditResponseHelper != null) {
883 // If the edit response helper dialog is open, we'll need to
884 // know if either of the choices were selected.
885 mEditResponseHelper.setWhichEvents(savedInstanceState.getInt(
886 BUNDLE_KEY_RESPONSE_WHICH_EVENTS, -1));
887 }
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -0800888 mUserSetResponse = savedInstanceState.getInt(
889 BUNDLE_KEY_USER_SET_ATTENDEE_RESPONSE,
890 Attendees.ATTENDEE_STATUS_NONE);
891 if (mUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
892 // If the response was set by the user before a configuration
893 // change, we'll need to know which choice was selected.
894 mWhichEvents = savedInstanceState.getInt(
895 BUNDLE_KEY_RESPONSE_WHICH_EVENTS, -1);
896 }
897
898 mReminders = Utils.readRemindersFromBundle(savedInstanceState);
Isaac Katzenelson320c1b12011-11-07 15:31:45 -0800899 }
900
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700901 if (mWindowStyle == DIALOG_WINDOW_STYLE) {
Michael Chancba7f1f2011-11-07 17:05:59 -0800902 mView = inflater.inflate(R.layout.event_info_dialog, container, false);
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700903 } else {
904 mView = inflater.inflate(R.layout.event_info, container, false);
905 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700906 mScrollView = (ScrollView) mView.findViewById(R.id.event_info_scroll_view);
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800907 mLoadingMsgView = mView.findViewById(R.id.event_info_loading_msg);
Paul Sliwowski1aba96a2013-05-20 20:27:12 -0700908 mErrorMsgView = mView.findViewById(R.id.event_info_error_msg);
Erik259b8f92011-01-12 14:01:12 -0800909 mTitle = (TextView) mView.findViewById(R.id.title);
Sara Ting75f53662012-04-09 15:37:10 -0700910 mWhenDateTime = (TextView) mView.findViewById(R.id.when_datetime);
Erik259b8f92011-01-12 14:01:12 -0800911 mWhere = (TextView) mView.findViewById(R.id.where);
Michael Chan99704a22011-11-11 10:24:37 -0800912 mDesc = (ExpandableTextView) mView.findViewById(R.id.description);
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -0700913 mHeadlines = mView.findViewById(R.id.event_info_headline);
James Kung4afba182012-12-18 23:12:08 -0800914 mLongAttendees = (AttendeesView) mView.findViewById(R.id.long_attendee_list);
915
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800916 mResponseRadioGroup = (RadioGroup) mView.findViewById(R.id.response_value);
Mason Tang2bebde72010-08-04 17:20:24 -0700917
Mason Tang4003d1c2010-08-17 13:50:45 -0700918 if (mUri == null) {
919 // restore event ID from bundle
920 mEventId = savedInstanceState.getLong(BUNDLE_KEY_EVENT_ID);
921 mUri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId);
922 mStartMillis = savedInstanceState.getLong(BUNDLE_KEY_START_MILLIS);
923 mEndMillis = savedInstanceState.getLong(BUNDLE_KEY_END_MILLIS);
924 }
925
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800926 mAnimateAlpha = ObjectAnimator.ofFloat(mScrollView, "Alpha", 0, 1);
927 mAnimateAlpha.setDuration(FADE_IN_TIME);
928 mAnimateAlpha.addListener(new AnimatorListenerAdapter() {
929 int defLayerType;
930
931 @Override
932 public void onAnimationStart(Animator animation) {
933 // Use hardware layer for better performance during animation
934 defLayerType = mScrollView.getLayerType();
935 mScrollView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
936 // Ensure that the loading message is gone before showing the
937 // event info
Isaac Katzenelson263b0292012-03-14 14:55:50 -0700938 mLoadingMsgView.removeCallbacks(mLoadingMsgAlphaUpdater);
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800939 mLoadingMsgView.setVisibility(View.GONE);
940 }
941
942 @Override
943 public void onAnimationCancel(Animator animation) {
944 mScrollView.setLayerType(defLayerType, null);
945 }
946
947 @Override
948 public void onAnimationEnd(Animator animation) {
949 mScrollView.setLayerType(defLayerType, null);
Isaac Katzenelson80d640f2012-04-20 09:21:28 -0700950 // Do not cross fade after the first time
951 mNoCrossFade = true;
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800952 }
953 });
954
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800955 mLoadingMsgView.setAlpha(0);
956 mScrollView.setAlpha(0);
Paul Sliwowski1aba96a2013-05-20 20:27:12 -0700957 mErrorMsgView.setVisibility(View.INVISIBLE);
Isaac Katzenelson263b0292012-03-14 14:55:50 -0700958 mLoadingMsgView.postDelayed(mLoadingMsgAlphaUpdater, LOADING_MSG_DELAY);
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800959
Mason Tang2bebde72010-08-04 17:20:24 -0700960 // start loading the data
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800961
Mason Tang2bebde72010-08-04 17:20:24 -0700962 mHandler.startQuery(TOKEN_QUERY_EVENT, null, mUri, EVENT_PROJECTION,
963 null, null, null);
964
Isaac Katzenelsond4e45fa2012-06-04 16:38:11 -0700965 View b = mView.findViewById(R.id.delete);
Michael Chan8ce3b7d2010-09-01 15:41:01 -0700966 b.setOnClickListener(new OnClickListener() {
967 @Override
968 public void onClick(View v) {
RoboErik69be8552011-02-14 16:51:59 -0800969 if (!mCanModifyCalendar) {
970 return;
971 }
Isaac Katzenelsond4e45fa2012-06-04 16:38:11 -0700972 mDeleteHelper =
973 new DeleteEventHelper(mContext, mActivity, !mIsDialog && !mIsTabletConfig /* exitWhenDone */);
Isaac Katzenelsonb0a313a2011-10-24 11:41:56 -0700974 mDeleteHelper.setDeleteNotificationListener(EventInfoFragment.this);
975 mDeleteHelper.setOnDismissListener(createDeleteOnDismissListener());
976 mDeleteDialogVisible = true;
977 mDeleteHelper.delete(mStartMillis, mEndMillis, mEventId, -1, onDeleteRunnable);
Isaac Katzenelsond4e45fa2012-06-04 16:38:11 -0700978 }
979 });
Michael Chan8ce3b7d2010-09-01 15:41:01 -0700980
James Kung4afba182012-12-18 23:12:08 -0800981 b = mView.findViewById(R.id.change_color);
982 b.setOnClickListener(new OnClickListener() {
983 @Override
984 public void onClick(View v) {
985 if (!mCanModifyCalendar) {
986 return;
987 }
James Kung4afba182012-12-18 23:12:08 -0800988 showEventColorPickerDialog();
989 }
990 });
991
Isaac Katzenelson10b60212011-06-28 17:59:14 -0700992 // Hide Edit/Delete buttons if in full screen mode on a phone
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700993 if (!mIsDialog && !mIsTabletConfig || mWindowStyle == EventInfoFragment.FULL_WINDOW_STYLE) {
Isaac Katzenelson60f01c22011-06-03 15:42:01 -0700994 mView.findViewById(R.id.event_info_buttons_container).setVisibility(View.GONE);
995 }
996
Sara Tingcb5f5682012-04-04 22:52:20 -0700997 // Create a listener for the email guests button
Sara Ting7ffa24c2012-08-28 15:44:37 -0700998 emailAttendeesButton = (Button) mView.findViewById(R.id.email_attendees_button);
Sara Tingcb5f5682012-04-04 22:52:20 -0700999 if (emailAttendeesButton != null) {
1000 emailAttendeesButton.setOnClickListener(new View.OnClickListener() {
1001 @Override
1002 public void onClick(View v) {
1003 emailAttendees();
1004 }
1005 });
1006 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001007
Sara Tingcb5f5682012-04-04 22:52:20 -07001008 // Create a listener for the add reminder button
Michael Chanb20942b2011-09-08 00:52:18 -07001009 View reminderAddButton = mView.findViewById(R.id.reminder_add);
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001010 View.OnClickListener addReminderOnClickListener = new View.OnClickListener() {
1011 @Override
1012 public void onClick(View v) {
1013 addReminder();
RoboErik8b5743c2011-09-27 16:07:09 -07001014 mUserModifiedReminders = true;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001015 }
1016 };
1017 reminderAddButton.setOnClickListener(addReminderOnClickListener);
1018
1019 // Set reminders variables
1020
1021 SharedPreferences prefs = GeneralPreferences.getSharedPreferences(mActivity);
1022 String defaultReminderString = prefs.getString(
1023 GeneralPreferences.KEY_DEFAULT_REMINDER, GeneralPreferences.NO_REMINDER_STRING);
1024 mDefaultReminderMinutes = Integer.parseInt(defaultReminderString);
1025 prepareReminders();
1026
Mason Tang2bebde72010-08-04 17:20:24 -07001027 return mView;
1028 }
1029
Isaac Katzenelsonac4350b2012-04-18 15:33:26 -07001030 private final Runnable onDeleteRunnable = new Runnable() {
Erik89ad0822011-01-18 15:55:17 -08001031 @Override
1032 public void run() {
RoboErik7c6236d2011-02-24 16:41:18 -08001033 if (EventInfoFragment.this.mIsPaused) {
1034 mDismissOnResume = true;
1035 return;
1036 }
Erik89ad0822011-01-18 15:55:17 -08001037 if (EventInfoFragment.this.isVisible()) {
1038 EventInfoFragment.this.dismiss();
1039 }
1040 }
1041 };
1042
Mason Tang2bebde72010-08-04 17:20:24 -07001043 private void updateTitle() {
1044 Resources res = getActivity().getResources();
1045 if (mCanModifyCalendar && !mIsOrganizer) {
1046 getActivity().setTitle(res.getString(R.string.event_info_title_invite));
1047 } else {
1048 getActivity().setTitle(res.getString(R.string.event_info_title));
1049 }
1050 }
1051
1052 /**
1053 * Initializes the event cursor, which is expected to point to the first
1054 * (and only) result from a query.
Paul Sliwowski1aba96a2013-05-20 20:27:12 -07001055 * @return false if the cursor is empty, true otherwise
Mason Tang2bebde72010-08-04 17:20:24 -07001056 */
1057 private boolean initEventCursor() {
1058 if ((mEventCursor == null) || (mEventCursor.getCount() == 0)) {
Paul Sliwowski1aba96a2013-05-20 20:27:12 -07001059 return false;
Mason Tang2bebde72010-08-04 17:20:24 -07001060 }
1061 mEventCursor.moveToFirst();
1062 mEventId = mEventCursor.getInt(EVENT_INDEX_ID);
1063 String rRule = mEventCursor.getString(EVENT_INDEX_RRULE);
Michael Chan66b20672010-12-20 13:50:28 -08001064 mIsRepeating = !TextUtils.isEmpty(rRule);
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -08001065 // mHasAlarm will be true if it was saved in the event already, or if
1066 // we've explicitly been provided reminders (e.g. during rotation).
1067 mHasAlarm = (mEventCursor.getInt(EVENT_INDEX_HAS_ALARM) == 1)? true :
1068 (mReminders != null && mReminders.size() > 0);
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001069 mMaxReminders = mEventCursor.getInt(EVENT_INDEX_MAX_REMINDERS);
1070 mCalendarAllowedReminders = mEventCursor.getString(EVENT_INDEX_ALLOWED_REMINDERS);
Paul Sliwowski1aba96a2013-05-20 20:27:12 -07001071 return true;
Mason Tang2bebde72010-08-04 17:20:24 -07001072 }
1073
Mason Tang2bebde72010-08-04 17:20:24 -07001074 @SuppressWarnings("fallthrough")
1075 private void initAttendeesCursor(View view) {
Isaac Katzenelson6bcafcf2012-05-02 18:25:36 -07001076 mOriginalAttendeeResponse = Attendees.ATTENDEE_STATUS_NONE;
Erikd845fbe2010-08-12 11:20:01 -07001077 mCalendarOwnerAttendeeId = EditEventHelper.ATTENDEE_ID_NONE;
Mason Tang2bebde72010-08-04 17:20:24 -07001078 mNumOfAttendees = 0;
1079 if (mAttendeesCursor != null) {
1080 mNumOfAttendees = mAttendeesCursor.getCount();
1081 if (mAttendeesCursor.moveToFirst()) {
1082 mAcceptedAttendees.clear();
1083 mDeclinedAttendees.clear();
1084 mTentativeAttendees.clear();
1085 mNoResponseAttendees.clear();
1086
1087 do {
1088 int status = mAttendeesCursor.getInt(ATTENDEES_INDEX_STATUS);
1089 String name = mAttendeesCursor.getString(ATTENDEES_INDEX_NAME);
1090 String email = mAttendeesCursor.getString(ATTENDEES_INDEX_EMAIL);
1091
Michael Chan83efa2d2012-04-24 17:42:21 -07001092 if (mAttendeesCursor.getInt(ATTENDEES_INDEX_RELATIONSHIP) ==
1093 Attendees.RELATIONSHIP_ORGANIZER) {
1094
1095 // Overwrites the one from Event table if available
1096 if (!TextUtils.isEmpty(name)) {
1097 mEventOrganizerDisplayName = name;
1098 if (!mIsOrganizer) {
1099 setVisibilityCommon(view, R.id.organizer_container, View.VISIBLE);
1100 setTextCommon(view, R.id.organizer, mEventOrganizerDisplayName);
1101 }
1102 }
1103 }
1104
Erikd845fbe2010-08-12 11:20:01 -07001105 if (mCalendarOwnerAttendeeId == EditEventHelper.ATTENDEE_ID_NONE &&
Mason Tang2bebde72010-08-04 17:20:24 -07001106 mCalendarOwnerAccount.equalsIgnoreCase(email)) {
1107 mCalendarOwnerAttendeeId = mAttendeesCursor.getInt(ATTENDEES_INDEX_ID);
1108 mOriginalAttendeeResponse = mAttendeesCursor.getInt(ATTENDEES_INDEX_STATUS);
1109 } else {
Michael Chan693ca602012-05-31 12:24:11 -07001110 String identity = null;
1111 String idNamespace = null;
1112
Sara Tingfac2d152012-05-31 14:59:57 -07001113 if (Utils.isJellybeanOrLater()) {
Michael Chan693ca602012-05-31 12:24:11 -07001114 identity = mAttendeesCursor.getString(ATTENDEES_INDEX_IDENTITY);
1115 idNamespace = mAttendeesCursor.getString(ATTENDEES_INDEX_ID_NAMESPACE);
1116 }
Sara Tingddbc0022012-04-26 17:08:46 -07001117
Mason Tang2bebde72010-08-04 17:20:24 -07001118 // Don't show your own status in the list because:
1119 // 1) it doesn't make sense for event without other guests.
1120 // 2) there's a spinner for that for events with guests.
1121 switch(status) {
1122 case Attendees.ATTENDEE_STATUS_ACCEPTED:
Isaac Katzenelsonfe25c502011-06-02 13:31:59 -07001123 mAcceptedAttendees.add(new Attendee(name, email,
Sara Tingddbc0022012-04-26 17:08:46 -07001124 Attendees.ATTENDEE_STATUS_ACCEPTED, identity,
1125 idNamespace));
Mason Tang2bebde72010-08-04 17:20:24 -07001126 break;
1127 case Attendees.ATTENDEE_STATUS_DECLINED:
Isaac Katzenelsonfe25c502011-06-02 13:31:59 -07001128 mDeclinedAttendees.add(new Attendee(name, email,
Sara Tingddbc0022012-04-26 17:08:46 -07001129 Attendees.ATTENDEE_STATUS_DECLINED, identity,
1130 idNamespace));
Mason Tang2bebde72010-08-04 17:20:24 -07001131 break;
Michael Chan8ce3b7d2010-09-01 15:41:01 -07001132 case Attendees.ATTENDEE_STATUS_TENTATIVE:
Isaac Katzenelsonfe25c502011-06-02 13:31:59 -07001133 mTentativeAttendees.add(new Attendee(name, email,
Sara Tingddbc0022012-04-26 17:08:46 -07001134 Attendees.ATTENDEE_STATUS_TENTATIVE, identity,
1135 idNamespace));
Michael Chan8ce3b7d2010-09-01 15:41:01 -07001136 break;
1137 default:
Isaac Katzenelsonfe25c502011-06-02 13:31:59 -07001138 mNoResponseAttendees.add(new Attendee(name, email,
Sara Tingddbc0022012-04-26 17:08:46 -07001139 Attendees.ATTENDEE_STATUS_NONE, identity,
1140 idNamespace));
Mason Tang2bebde72010-08-04 17:20:24 -07001141 }
1142 }
1143 } while (mAttendeesCursor.moveToNext());
1144 mAttendeesCursor.moveToFirst();
1145
1146 updateAttendees(view);
1147 }
1148 }
Mason Tang2bebde72010-08-04 17:20:24 -07001149 }
1150
1151 @Override
Mason Tang4003d1c2010-08-17 13:50:45 -07001152 public void onSaveInstanceState(Bundle outState) {
1153 super.onSaveInstanceState(outState);
1154 outState.putLong(BUNDLE_KEY_EVENT_ID, mEventId);
1155 outState.putLong(BUNDLE_KEY_START_MILLIS, mStartMillis);
1156 outState.putLong(BUNDLE_KEY_END_MILLIS, mEndMillis);
Michael Chan71d08832010-08-25 18:28:59 -07001157 outState.putBoolean(BUNDLE_KEY_IS_DIALOG, mIsDialog);
Isaac Katzenelson7ef29812011-10-25 18:00:50 -07001158 outState.putInt(BUNDLE_KEY_WINDOW_STYLE, mWindowStyle);
Isaac Katzenelsonb0a313a2011-10-24 11:41:56 -07001159 outState.putBoolean(BUNDLE_KEY_DELETE_DIALOG_VISIBLE, mDeleteDialogVisible);
James Kung4afba182012-12-18 23:12:08 -08001160 outState.putInt(BUNDLE_KEY_CALENDAR_COLOR, mCalendarColor);
James Kungf56b1492013-03-07 15:10:13 -08001161 outState.putBoolean(BUNDLE_KEY_CALENDAR_COLOR_INIT, mCalendarColorInitialized);
James Kung4afba182012-12-18 23:12:08 -08001162 outState.putInt(BUNDLE_KEY_ORIGINAL_COLOR, mOriginalColor);
James Kungf56b1492013-03-07 15:10:13 -08001163 outState.putBoolean(BUNDLE_KEY_ORIGINAL_COLOR_INIT, mOriginalColorInitialized);
James Kung4afba182012-12-18 23:12:08 -08001164 outState.putInt(BUNDLE_KEY_CURRENT_COLOR, mCurrentColor);
James Kungf56b1492013-03-07 15:10:13 -08001165 outState.putBoolean(BUNDLE_KEY_CURRENT_COLOR_INIT, mCurrentColorInitialized);
James Kung497a6252013-05-17 14:47:33 -07001166 outState.putInt(BUNDLE_KEY_CURRENT_COLOR_KEY, mCurrentColorKey);
James Kungf56b1492013-03-07 15:10:13 -08001167
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08001168 // We'll need the temporary response for configuration changes.
1169 outState.putInt(BUNDLE_KEY_TENTATIVE_USER_RESPONSE, mTentativeUserSetResponse);
1170 if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE &&
1171 mEditResponseHelper != null) {
1172 outState.putInt(BUNDLE_KEY_RESPONSE_WHICH_EVENTS,
1173 mEditResponseHelper.getWhichEvents());
1174 }
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -08001175
1176 // Save the current response.
1177 int response;
1178 if (mAttendeeResponseFromIntent != Attendees.ATTENDEE_STATUS_NONE) {
1179 response = mAttendeeResponseFromIntent;
1180 } else {
1181 response = mOriginalAttendeeResponse;
1182 }
1183 outState.putInt(BUNDLE_KEY_ATTENDEE_RESPONSE, response);
1184 if (mUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
1185 response = mUserSetResponse;
1186 outState.putInt(BUNDLE_KEY_USER_SET_ATTENDEE_RESPONSE, response);
1187 outState.putInt(BUNDLE_KEY_RESPONSE_WHICH_EVENTS, mWhichEvents);
1188 }
1189
1190 // Save the reminders.
1191 mReminders = EventViewUtils.reminderItemsToReminders(mReminderViews,
1192 mReminderMinuteValues, mReminderMethodValues);
1193 int numReminders = mReminders.size();
1194 ArrayList<Integer> reminderMinutes =
1195 new ArrayList<Integer>(numReminders);
1196 ArrayList<Integer> reminderMethods =
1197 new ArrayList<Integer>(numReminders);
1198 for (ReminderEntry reminder : mReminders) {
1199 reminderMinutes.add(reminder.getMinutes());
1200 reminderMethods.add(reminder.getMethod());
1201 }
1202 outState.putIntegerArrayList(
1203 BUNDLE_KEY_REMINDER_MINUTES, reminderMinutes);
1204 outState.putIntegerArrayList(
1205 BUNDLE_KEY_REMINDER_METHODS, reminderMethods);
Isaac Katzenelson60f01c22011-06-03 15:42:01 -07001206 }
1207
Isaac Katzenelson60f01c22011-06-03 15:42:01 -07001208 @Override
1209 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
1210 super.onCreateOptionsMenu(menu, inflater);
James Kung1dadfa22013-04-11 19:22:41 -07001211 // Show color/edit/delete buttons only in non-dialog configuration
Isaac Katzenelson7ef29812011-10-25 18:00:50 -07001212 if (!mIsDialog && !mIsTabletConfig || mWindowStyle == EventInfoFragment.FULL_WINDOW_STYLE) {
Isaac Katzenelson60f01c22011-06-03 15:42:01 -07001213 inflater.inflate(R.menu.event_info_title_bar, menu);
RoboErikd8353fb2011-07-21 11:28:11 -07001214 mMenu = menu;
1215 updateMenu();
Isaac Katzenelson60f01c22011-06-03 15:42:01 -07001216 }
Mason Tang4003d1c2010-08-17 13:50:45 -07001217 }
1218
RoboErikd8353fb2011-07-21 11:28:11 -07001219 @Override
1220 public boolean onOptionsItemSelected(MenuItem item) {
1221
Isaac Katzenelson7ef29812011-10-25 18:00:50 -07001222 // If we're a dialog we don't want to handle menu buttons
1223 if (mIsDialog) {
RoboErikd8353fb2011-07-21 11:28:11 -07001224 return false;
1225 }
1226 // Handles option menu selections:
1227 // Home button - close event info activity and start the main calendar
1228 // one
1229 // Edit button - start the event edit activity and close the info
1230 // activity
1231 // Delete button - start a delete query that calls a runnable that close
1232 // the info activity
1233
Michael Chanbb6d9272012-08-17 17:32:58 -07001234 final int itemId = item.getItemId();
1235 if (itemId == android.R.id.home) {
1236 Utils.returnToCalendarHome(mContext);
1237 mActivity.finish();
1238 return true;
1239 } else if (itemId == R.id.info_action_edit) {
James Kung1d1b1e42013-03-06 19:49:23 -08001240 doEdit();
Michael Chanbb6d9272012-08-17 17:32:58 -07001241 mActivity.finish();
1242 } else if (itemId == R.id.info_action_delete) {
1243 mDeleteHelper =
1244 new DeleteEventHelper(mActivity, mActivity, true /* exitWhenDone */);
1245 mDeleteHelper.setDeleteNotificationListener(EventInfoFragment.this);
1246 mDeleteHelper.setOnDismissListener(createDeleteOnDismissListener());
1247 mDeleteDialogVisible = true;
1248 mDeleteHelper.delete(mStartMillis, mEndMillis, mEventId, -1, onDeleteRunnable);
James Kung4afba182012-12-18 23:12:08 -08001249 } else if (itemId == R.id.info_action_change_color) {
1250 showEventColorPickerDialog();
RoboErikd8353fb2011-07-21 11:28:11 -07001251 }
1252 return super.onOptionsItemSelected(item);
1253 }
Mason Tang4003d1c2010-08-17 13:50:45 -07001254
James Kung4afba182012-12-18 23:12:08 -08001255 private void showEventColorPickerDialog() {
James Kung2fca0242013-04-02 16:09:50 -07001256 if (mColorPickerDialog == null) {
1257 mColorPickerDialog = EventColorPickerDialog.newInstance(mColors, mCurrentColor,
1258 mCalendarColor, mIsTabletConfig);
1259 mColorPickerDialog.setOnColorSelectedListener(this);
James Kung4afba182012-12-18 23:12:08 -08001260 }
James Kung95e95382013-03-20 12:14:33 -07001261 final FragmentManager fragmentManager = getFragmentManager();
1262 fragmentManager.executePendingTransactions();
James Kung2fca0242013-04-02 16:09:50 -07001263 if (!mColorPickerDialog.isAdded()) {
1264 mColorPickerDialog.show(fragmentManager, COLOR_PICKER_DIALOG_TAG);
James Kung4afba182012-12-18 23:12:08 -08001265 }
1266 }
1267
1268 private boolean saveEventColor() {
1269 if (mCurrentColor == mOriginalColor) {
1270 return false;
1271 }
1272
1273 ContentValues values = new ContentValues();
1274 if (mCurrentColor != mCalendarColor) {
James Kung497a6252013-05-17 14:47:33 -07001275 values.put(Events.EVENT_COLOR_KEY, mCurrentColorKey);
James Kung4afba182012-12-18 23:12:08 -08001276 } else {
1277 values.put(Events.EVENT_COLOR_KEY, NO_EVENT_COLOR);
1278 }
1279 Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId);
1280 mHandler.startUpdate(mHandler.getNextToken(), null, uri, values,
1281 null, null, Utils.UNDO_DELAY);
1282 return true;
1283 }
1284
Mason Tang4003d1c2010-08-17 13:50:45 -07001285 @Override
Sam Blitzstein9d4a9522012-10-17 14:39:38 -07001286 public void onStop() {
1287 Activity act = getActivity();
1288 if (!mEventDeletionStarted && act != null && !act.isChangingConfigurations()) {
James Kung497a6252013-05-17 14:47:33 -07001289
Isaac Katzenelsonac4350b2012-04-18 15:33:26 -07001290 boolean responseSaved = saveResponse();
James Kung4afba182012-12-18 23:12:08 -08001291 boolean eventColorSaved = saveEventColor();
1292 if (saveReminders() || responseSaved || eventColorSaved) {
Isaac Katzenelsonb33cdf42011-10-14 18:15:18 -07001293 Toast.makeText(getActivity(), R.string.saving_event, Toast.LENGTH_SHORT).show();
1294 }
Mason Tang2bebde72010-08-04 17:20:24 -07001295 }
Sam Blitzstein9d4a9522012-10-17 14:39:38 -07001296 super.onStop();
Mason Tang2bebde72010-08-04 17:20:24 -07001297 }
1298
1299 @Override
1300 public void onDestroy() {
Mason Tang2bebde72010-08-04 17:20:24 -07001301 if (mEventCursor != null) {
1302 mEventCursor.close();
1303 }
1304 if (mCalendarsCursor != null) {
1305 mCalendarsCursor.close();
1306 }
1307 if (mAttendeesCursor != null) {
1308 mAttendeesCursor.close();
1309 }
Michael Chan71d08832010-08-25 18:28:59 -07001310 super.onDestroy();
Mason Tang2bebde72010-08-04 17:20:24 -07001311 }
1312
Mason Tang2bebde72010-08-04 17:20:24 -07001313 /**
1314 * Asynchronously saves the response to an invitation if the user changed
1315 * the response. Returns true if the database will be updated.
1316 *
Mason Tang2bebde72010-08-04 17:20:24 -07001317 * @return true if the database will be changed
1318 */
1319 private boolean saveResponse() {
1320 if (mAttendeesCursor == null || mEventCursor == null) {
1321 return false;
1322 }
Michael Chanf92f46b2010-10-27 18:59:05 -07001323
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08001324 int status = getResponseFromButtonId(
1325 mResponseRadioGroup.getCheckedRadioButtonId());
Michael Chanf92f46b2010-10-27 18:59:05 -07001326 if (status == Attendees.ATTENDEE_STATUS_NONE) {
Mason Tang2bebde72010-08-04 17:20:24 -07001327 return false;
1328 }
1329
Mason Tang2bebde72010-08-04 17:20:24 -07001330 // If the status has not changed, then don't update the database
1331 if (status == mOriginalAttendeeResponse) {
1332 return false;
1333 }
1334
1335 // If we never got an owner attendee id we can't set the status
Erikd845fbe2010-08-12 11:20:01 -07001336 if (mCalendarOwnerAttendeeId == EditEventHelper.ATTENDEE_ID_NONE) {
Mason Tang2bebde72010-08-04 17:20:24 -07001337 return false;
1338 }
1339
1340 if (!mIsRepeating) {
1341 // This is a non-repeating event
1342 updateResponse(mEventId, mCalendarOwnerAttendeeId, status);
Sam Blitzstein9d4a9522012-10-17 14:39:38 -07001343 mOriginalAttendeeResponse = status;
Mason Tang2bebde72010-08-04 17:20:24 -07001344 return true;
1345 }
1346
James Kung96267162013-05-01 11:42:57 -07001347 if (DEBUG) {
1348 Log.d(TAG, "Repeating event: mWhichEvents=" + mWhichEvents);
1349 }
Mason Tang2bebde72010-08-04 17:20:24 -07001350 // This is a repeating event
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08001351 switch (mWhichEvents) {
Mason Tang2bebde72010-08-04 17:20:24 -07001352 case -1:
1353 return false;
1354 case UPDATE_SINGLE:
Andy McFaddenc928e3d2011-06-13 09:53:20 -07001355 createExceptionResponse(mEventId, status);
Sam Blitzstein9d4a9522012-10-17 14:39:38 -07001356 mOriginalAttendeeResponse = status;
Mason Tang2bebde72010-08-04 17:20:24 -07001357 return true;
1358 case UPDATE_ALL:
1359 updateResponse(mEventId, mCalendarOwnerAttendeeId, status);
Sam Blitzstein9d4a9522012-10-17 14:39:38 -07001360 mOriginalAttendeeResponse = status;
Mason Tang2bebde72010-08-04 17:20:24 -07001361 return true;
1362 default:
1363 Log.e(TAG, "Unexpected choice for updating invitation response");
1364 break;
1365 }
1366 return false;
1367 }
1368
1369 private void updateResponse(long eventId, long attendeeId, int status) {
1370 // Update the attendee status in the attendees table. the provider
1371 // takes care of updating the self attendance status.
1372 ContentValues values = new ContentValues();
1373
1374 if (!TextUtils.isEmpty(mCalendarOwnerAccount)) {
1375 values.put(Attendees.ATTENDEE_EMAIL, mCalendarOwnerAccount);
1376 }
1377 values.put(Attendees.ATTENDEE_STATUS, status);
1378 values.put(Attendees.EVENT_ID, eventId);
1379
1380 Uri uri = ContentUris.withAppendedId(Attendees.CONTENT_URI, attendeeId);
1381
1382 mHandler.startUpdate(mHandler.getNextToken(), null, uri, values,
1383 null, null, Utils.UNDO_DELAY);
1384 }
1385
Andy McFaddenc928e3d2011-06-13 09:53:20 -07001386 /**
1387 * Creates an exception to a recurring event. The only change we're making is to the
1388 * "self attendee status" value. The provider will take care of updating the corresponding
1389 * Attendees.attendeeStatus entry.
1390 *
1391 * @param eventId The recurring event.
1392 * @param status The new value for selfAttendeeStatus.
1393 */
1394 private void createExceptionResponse(long eventId, int status) {
Mason Tang2bebde72010-08-04 17:20:24 -07001395 ContentValues values = new ContentValues();
Mason Tang2bebde72010-08-04 17:20:24 -07001396 values.put(Events.ORIGINAL_INSTANCE_TIME, mStartMillis);
Mason Tang2bebde72010-08-04 17:20:24 -07001397 values.put(Events.SELF_ATTENDEE_STATUS, status);
Andy McFaddenc928e3d2011-06-13 09:53:20 -07001398 values.put(Events.STATUS, Events.STATUS_CONFIRMED);
Mason Tang2bebde72010-08-04 17:20:24 -07001399
Erik364309f2010-12-23 14:26:26 -08001400 ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
Andy McFadden79b2c8c2011-06-30 15:26:05 -07001401 Uri exceptionUri = Uri.withAppendedPath(Events.CONTENT_EXCEPTION_URI,
Andy McFaddenc928e3d2011-06-13 09:53:20 -07001402 String.valueOf(eventId));
1403 ops.add(ContentProviderOperation.newInsert(exceptionUri).withValues(values).build());
Erik364309f2010-12-23 14:26:26 -08001404
Andy McFaddenc928e3d2011-06-13 09:53:20 -07001405 mHandler.startBatch(mHandler.getNextToken(), null, CalendarContract.AUTHORITY, ops,
1406 Utils.UNDO_DELAY);
1407 }
Mason Tang2bebde72010-08-04 17:20:24 -07001408
Michael Chanf92f46b2010-10-27 18:59:05 -07001409 public static int getResponseFromButtonId(int buttonId) {
1410 int response;
Michael Chanbb6d9272012-08-17 17:32:58 -07001411 if (buttonId == R.id.response_yes) {
1412 response = Attendees.ATTENDEE_STATUS_ACCEPTED;
1413 } else if (buttonId == R.id.response_maybe) {
1414 response = Attendees.ATTENDEE_STATUS_TENTATIVE;
1415 } else if (buttonId == R.id.response_no) {
1416 response = Attendees.ATTENDEE_STATUS_DECLINED;
1417 } else {
1418 response = Attendees.ATTENDEE_STATUS_NONE;
Mason Tang2bebde72010-08-04 17:20:24 -07001419 }
Michael Chanf92f46b2010-10-27 18:59:05 -07001420 return response;
1421 }
1422
1423 public static int findButtonIdForResponse(int response) {
1424 int buttonId;
1425 switch (response) {
1426 case Attendees.ATTENDEE_STATUS_ACCEPTED:
1427 buttonId = R.id.response_yes;
1428 break;
1429 case Attendees.ATTENDEE_STATUS_TENTATIVE:
1430 buttonId = R.id.response_maybe;
1431 break;
1432 case Attendees.ATTENDEE_STATUS_DECLINED:
1433 buttonId = R.id.response_no;
1434 break;
1435 default:
1436 buttonId = -1;
1437 }
1438 return buttonId;
Mason Tang2bebde72010-08-04 17:20:24 -07001439 }
1440
1441 private void doEdit() {
Erikc41b99b2010-11-24 10:27:13 -08001442 Context c = getActivity();
1443 // This ensures that we aren't in the process of closing and have been
1444 // unattached already
1445 if (c != null) {
James Kung1d1b1e42013-03-06 19:49:23 -08001446 Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId);
1447 Intent intent = new Intent(Intent.ACTION_EDIT, uri);
1448 intent.setClass(mActivity, EditEventActivity.class);
1449 intent.putExtra(EXTRA_EVENT_BEGIN_TIME, mStartMillis);
1450 intent.putExtra(EXTRA_EVENT_END_TIME, mEndMillis);
1451 intent.putExtra(EXTRA_EVENT_ALL_DAY, mAllDay);
1452 intent.putExtra(EditEventActivity.EXTRA_EVENT_COLOR, mCurrentColor);
1453 intent.putExtra(EditEventActivity.EXTRA_EVENT_REMINDERS, EventViewUtils
1454 .reminderItemsToReminders(mReminderViews, mReminderMinuteValues,
1455 mReminderMethodValues));
1456 intent.putExtra(EVENT_EDIT_ON_LAUNCH, true);
1457 startActivity(intent);
Erikc41b99b2010-11-24 10:27:13 -08001458 }
Mason Tang2bebde72010-08-04 17:20:24 -07001459 }
1460
Paul Sliwowski1aba96a2013-05-20 20:27:12 -07001461 private void displayEventNotFound() {
1462 mErrorMsgView.setVisibility(View.VISIBLE);
1463 mScrollView.setVisibility(View.GONE);
1464 mLoadingMsgView.setVisibility(View.GONE);
1465 }
1466
Mason Tang2bebde72010-08-04 17:20:24 -07001467 private void updateEvent(View view) {
Isaac Katzenelsonb7762cf2011-06-09 14:04:42 -07001468 if (mEventCursor == null || view == null) {
Mason Tang2bebde72010-08-04 17:20:24 -07001469 return;
1470 }
1471
Michael Chan5f5ef752012-05-24 17:00:21 -07001472 Context context = view.getContext();
1473 if (context == null) {
1474 return;
1475 }
1476
Mason Tang2bebde72010-08-04 17:20:24 -07001477 String eventName = mEventCursor.getString(EVENT_INDEX_TITLE);
1478 if (eventName == null || eventName.length() == 0) {
1479 eventName = getActivity().getString(R.string.no_title_label);
1480 }
1481
Sara Tingda3ee392012-12-10 15:18:26 -08001482 // 3rd parties might not have specified the start/end time when firing the
1483 // Events.CONTENT_URI intent. Update these with values read from the db.
1484 if (mStartMillis == 0 && mEndMillis == 0) {
1485 mStartMillis = mEventCursor.getLong(EVENT_INDEX_DTSTART);
1486 mEndMillis = mEventCursor.getLong(EVENT_INDEX_DTEND);
1487 if (mEndMillis == 0) {
1488 String duration = mEventCursor.getString(EVENT_INDEX_DURATION);
1489 if (!TextUtils.isEmpty(duration)) {
1490 try {
1491 Duration d = new Duration();
1492 d.parse(duration);
1493 long endMillis = mStartMillis + d.getMillis();
1494 if (endMillis >= mStartMillis) {
1495 mEndMillis = endMillis;
1496 } else {
1497 Log.d(TAG, "Invalid duration string: " + duration);
1498 }
1499 } catch (DateException e) {
1500 Log.d(TAG, "Error parsing duration string " + duration, e);
1501 }
1502 }
1503 if (mEndMillis == 0) {
1504 mEndMillis = mStartMillis;
1505 }
1506 }
1507 }
1508
Michael Chan8b1119b2012-01-06 16:04:55 -08001509 mAllDay = mEventCursor.getInt(EVENT_INDEX_ALL_DAY) != 0;
Mason Tang2bebde72010-08-04 17:20:24 -07001510 String location = mEventCursor.getString(EVENT_INDEX_EVENT_LOCATION);
1511 String description = mEventCursor.getString(EVENT_INDEX_DESCRIPTION);
1512 String rRule = mEventCursor.getString(EVENT_INDEX_RRULE);
Isaac Katzenelsonf6f79772011-06-02 16:29:18 -07001513 String eventTimezone = mEventCursor.getString(EVENT_INDEX_EVENT_TIMEZONE);
Mason Tang2bebde72010-08-04 17:20:24 -07001514
James Kung497a6252013-05-17 14:47:33 -07001515 mHeadlines.setBackgroundColor(mCurrentColor);
Mason Tang2bebde72010-08-04 17:20:24 -07001516
Sara Ting4e926272012-04-19 10:41:56 -07001517 // What
1518 if (eventName != null) {
1519 setTextCommon(view, R.id.title, eventName);
1520 }
1521
Mason Tang2bebde72010-08-04 17:20:24 -07001522 // When
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001523 // Set the date and repeats (if any)
Sara Ting75f53662012-04-09 15:37:10 -07001524 String localTimezone = Utils.getTimeZone(mActivity, mTZUpdater);
Michael Chan5f5ef752012-05-24 17:00:21 -07001525
Sara Ting23acd262012-04-20 13:27:39 -07001526 Resources resources = context.getResources();
1527 String displayedDatetime = Utils.getDisplayedDatetime(mStartMillis, mEndMillis,
1528 System.currentTimeMillis(), localTimezone, mAllDay, context);
Michael Chane8e55722012-05-30 13:59:34 -07001529
1530 String displayedTimezone = null;
1531 if (!mAllDay) {
1532 displayedTimezone = Utils.getDisplayedTimezone(mStartMillis, localTimezone,
1533 eventTimezone);
Sara Ting23acd262012-04-20 13:27:39 -07001534 }
1535 // Display the datetime. Make the timezone (if any) transparent.
1536 if (displayedTimezone == null) {
1537 setTextCommon(view, R.id.when_datetime, displayedDatetime);
1538 } else {
Michael Chane8e55722012-05-30 13:59:34 -07001539 int timezoneIndex = displayedDatetime.length();
1540 displayedDatetime += " " + displayedTimezone;
Sara Ting23acd262012-04-20 13:27:39 -07001541 SpannableStringBuilder sb = new SpannableStringBuilder(displayedDatetime);
1542 ForegroundColorSpan transparentColorSpan = new ForegroundColorSpan(
1543 resources.getColor(R.color.event_info_headline_transparent_color));
1544 sb.setSpan(transparentColorSpan, timezoneIndex, displayedDatetime.length(),
1545 Spannable.SPAN_INCLUSIVE_INCLUSIVE);
1546 setTextCommon(view, R.id.when_datetime, sb);
1547 }
Isaac Katzenelson74c90322011-06-02 15:20:29 -07001548
Sara Ting75f53662012-04-09 15:37:10 -07001549 // Display the repeat string (if any)
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001550 String repeatString = null;
Michael Chanbfa0e3f2010-12-20 12:36:55 -08001551 if (!TextUtils.isEmpty(rRule)) {
Mason Tang2bebde72010-08-04 17:20:24 -07001552 EventRecurrence eventRecurrence = new EventRecurrence();
1553 eventRecurrence.parse(rRule);
Sara Ting75f53662012-04-09 15:37:10 -07001554 Time date = new Time(localTimezone);
1555 date.set(mStartMillis);
Michael Chan8b1119b2012-01-06 16:04:55 -08001556 if (mAllDay) {
Mason Tang2bebde72010-08-04 17:20:24 -07001557 date.timezone = Time.TIMEZONE_UTC;
1558 }
Mason Tang2bebde72010-08-04 17:20:24 -07001559 eventRecurrence.setStartDate(date);
Michael Chanb21c6382013-03-14 02:53:30 -07001560 repeatString = EventRecurrenceFormatter.getRepeatString(mContext, resources,
1561 eventRecurrence, true);
Mason Tang2bebde72010-08-04 17:20:24 -07001562 }
Sara Ting75f53662012-04-09 15:37:10 -07001563 if (repeatString == null) {
1564 view.findViewById(R.id.when_repeat).setVisibility(View.GONE);
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001565 } else {
Sara Ting75f53662012-04-09 15:37:10 -07001566 setTextCommon(view, R.id.when_repeat, repeatString);
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001567 }
1568
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001569 // Organizer view is setup in the updateCalendar method
1570
Mason Tang2bebde72010-08-04 17:20:24 -07001571
1572 // Where
Michael Chanddfb59d2011-01-12 15:41:21 -08001573 if (location == null || location.trim().length() == 0) {
Mason Tang2bebde72010-08-04 17:20:24 -07001574 setVisibilityCommon(view, R.id.where, View.GONE);
1575 } else {
Erik259b8f92011-01-12 14:01:12 -08001576 final TextView textView = mWhere;
Mason Tang2bebde72010-08-04 17:20:24 -07001577 if (textView != null) {
Michael Chanddfb59d2011-01-12 15:41:21 -08001578 textView.setAutoLinkMask(0);
1579 textView.setText(location.trim());
Andy McFaddenaf577fd2011-11-07 11:08:14 -08001580 try {
Sam Blitzstein29dc76a2012-11-19 10:46:54 -08001581 textView.setText(Utils.extendedLinkify(textView.getText().toString(), true));
1582
1583 // Linkify.addLinks() sets the TextView movement method if it finds any links.
Sara Tingda3ee392012-12-10 15:18:26 -08001584 // We must do the same here, in case linkify by itself did not find any.
Sam Blitzstein29dc76a2012-11-19 10:46:54 -08001585 // (This is cloned from Linkify.addLinkMovementMethod().)
1586 MovementMethod mm = textView.getMovementMethod();
1587 if ((mm == null) || !(mm instanceof LinkMovementMethod)) {
1588 if (textView.getLinksClickable()) {
1589 textView.setMovementMethod(LinkMovementMethod.getInstance());
1590 }
1591 }
Andy McFaddenaf577fd2011-11-07 11:08:14 -08001592 } catch (Exception ex) {
1593 // unexpected
1594 Log.e(TAG, "Linkification failed", ex);
1595 }
Andy McFadden73b07652011-08-23 15:45:09 -07001596
Michael Chanddfb59d2011-01-12 15:41:21 -08001597 textView.setOnTouchListener(new OnTouchListener() {
Andy McFaddenc928e3d2011-06-13 09:53:20 -07001598 @Override
Michael Chanddfb59d2011-01-12 15:41:21 -08001599 public boolean onTouch(View v, MotionEvent event) {
1600 try {
1601 return v.onTouchEvent(event);
1602 } catch (ActivityNotFoundException e) {
1603 // ignore
1604 return true;
Mason Tang2bebde72010-08-04 17:20:24 -07001605 }
Michael Chanddfb59d2011-01-12 15:41:21 -08001606 }
1607 });
Mason Tang2bebde72010-08-04 17:20:24 -07001608 }
1609 }
1610
1611 // Description
Michael Chan352e1a22010-09-28 05:15:08 -07001612 if (description != null && description.length() != 0) {
Michael Chan99704a22011-11-11 10:24:37 -08001613 mDesc.setText(description);
Mason Tang2bebde72010-08-04 17:20:24 -07001614 }
Mason Tang2bebde72010-08-04 17:20:24 -07001615
Michael Chan2c8485c2012-05-09 10:23:45 -07001616 // Launch Custom App
Sara Tingfac2d152012-05-31 14:59:57 -07001617 if (Utils.isJellybeanOrLater()) {
Michael Chan693ca602012-05-31 12:24:11 -07001618 updateCustomAppButton();
1619 }
Michael Chan2c8485c2012-05-09 10:23:45 -07001620 }
1621
1622 private void updateCustomAppButton() {
1623 buttonSetup: {
1624 final Button launchButton = (Button) mView.findViewById(R.id.launch_custom_app_button);
1625 if (launchButton == null)
1626 break buttonSetup;
1627
1628 final String customAppPackage = mEventCursor.getString(EVENT_INDEX_CUSTOM_APP_PACKAGE);
1629 final String customAppUri = mEventCursor.getString(EVENT_INDEX_CUSTOM_APP_URI);
1630
1631 if (TextUtils.isEmpty(customAppPackage) || TextUtils.isEmpty(customAppUri))
1632 break buttonSetup;
1633
1634 PackageManager pm = mContext.getPackageManager();
1635 if (pm == null)
1636 break buttonSetup;
1637
1638 ApplicationInfo info;
1639 try {
1640 info = pm.getApplicationInfo(customAppPackage, 0);
1641 if (info == null)
1642 break buttonSetup;
1643 } catch (NameNotFoundException e) {
1644 break buttonSetup;
1645 }
1646
1647 Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId);
1648 final Intent intent = new Intent(CalendarContract.ACTION_HANDLE_CUSTOM_EVENT, uri);
1649 intent.setPackage(customAppPackage);
1650 intent.putExtra(CalendarContract.EXTRA_CUSTOM_APP_URI, customAppUri);
1651 intent.putExtra(EXTRA_EVENT_BEGIN_TIME, mStartMillis);
1652
1653 // See if we have a taker for our intent
1654 if (pm.resolveActivity(intent, 0) == null)
1655 break buttonSetup;
1656
1657 Drawable icon = pm.getApplicationIcon(info);
1658 if (icon != null) {
1659
1660 Drawable[] d = launchButton.getCompoundDrawables();
1661 icon.setBounds(0, 0, mCustomAppIconSize, mCustomAppIconSize);
1662 launchButton.setCompoundDrawables(icon, d[1], d[2], d[3]);
1663 }
1664
1665 CharSequence label = pm.getApplicationLabel(info);
1666 if (label != null && label.length() != 0) {
1667 launchButton.setText(label);
1668 } else if (icon == null) {
1669 // No icon && no label. Hide button?
1670 break buttonSetup;
1671 }
1672
1673 // Launch custom app
1674 launchButton.setOnClickListener(new View.OnClickListener() {
1675 @Override
1676 public void onClick(View v) {
1677 try {
1678 startActivityForResult(intent, 0);
1679 } catch (ActivityNotFoundException e) {
1680 // Shouldn't happen as we checked it already
1681 setVisibilityCommon(mView, R.id.launch_custom_app_container, View.GONE);
1682 }
1683 }
1684 });
1685
1686 setVisibilityCommon(mView, R.id.launch_custom_app_container, View.VISIBLE);
1687 return;
1688
1689 }
1690
1691 setVisibilityCommon(mView, R.id.launch_custom_app_container, View.GONE);
1692 return;
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -08001693 }
Sara Ting75f53662012-04-09 15:37:10 -07001694
Erik259b8f92011-01-12 14:01:12 -08001695 private void sendAccessibilityEvent() {
Andy McFaddenef31a982011-06-09 07:38:56 -07001696 AccessibilityManager am =
1697 (AccessibilityManager) getActivity().getSystemService(Service.ACCESSIBILITY_SERVICE);
Erik259b8f92011-01-12 14:01:12 -08001698 if (!am.isEnabled()) {
1699 return;
1700 }
1701
1702 AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_FOCUSED);
Paul Sliwowski1aba96a2013-05-20 20:27:12 -07001703 event.setClassName(EventInfoFragment.class.getName());
Erik259b8f92011-01-12 14:01:12 -08001704 event.setPackageName(getActivity().getPackageName());
1705 List<CharSequence> text = event.getText();
1706
Michael Chan99704a22011-11-11 10:24:37 -08001707 addFieldToAccessibilityEvent(text, mTitle, null);
Sara Ting75f53662012-04-09 15:37:10 -07001708 addFieldToAccessibilityEvent(text, mWhenDateTime, null);
Michael Chan99704a22011-11-11 10:24:37 -08001709 addFieldToAccessibilityEvent(text, mWhere, null);
1710 addFieldToAccessibilityEvent(text, null, mDesc);
Erik259b8f92011-01-12 14:01:12 -08001711
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08001712 if (mResponseRadioGroup.getVisibility() == View.VISIBLE) {
1713 int id = mResponseRadioGroup.getCheckedRadioButtonId();
Erik259b8f92011-01-12 14:01:12 -08001714 if (id != View.NO_ID) {
1715 text.add(((TextView) getView().findViewById(R.id.response_label)).getText());
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08001716 text.add((((RadioButton) (mResponseRadioGroup.findViewById(id)))
1717 .getText() + PERIOD_SPACE));
Erik259b8f92011-01-12 14:01:12 -08001718 }
1719 }
1720
1721 am.sendAccessibilityEvent(event);
1722 }
1723
Michael Chan99704a22011-11-11 10:24:37 -08001724 private void addFieldToAccessibilityEvent(List<CharSequence> text, TextView tv,
1725 ExpandableTextView etv) {
Michael Chan33893972011-11-16 12:45:53 -08001726 CharSequence cs;
Michael Chan99704a22011-11-11 10:24:37 -08001727 if (tv != null) {
Michael Chan33893972011-11-16 12:45:53 -08001728 cs = tv.getText();
Michael Chan99704a22011-11-11 10:24:37 -08001729 } else if (etv != null) {
Michael Chan33893972011-11-16 12:45:53 -08001730 cs = etv.getText();
Michael Chan99704a22011-11-11 10:24:37 -08001731 } else {
Isaac Katzenelson9ceed1f2011-06-08 17:26:26 -07001732 return;
1733 }
Michael Chan99704a22011-11-11 10:24:37 -08001734
Michael Chan33893972011-11-16 12:45:53 -08001735 if (!TextUtils.isEmpty(cs)) {
1736 cs = cs.toString().trim();
1737 if (cs.length() > 0) {
1738 text.add(cs);
1739 text.add(PERIOD_SPACE);
1740 }
Erik259b8f92011-01-12 14:01:12 -08001741 }
1742 }
1743
Mason Tang2bebde72010-08-04 17:20:24 -07001744 private void updateCalendar(View view) {
James Kung4afba182012-12-18 23:12:08 -08001745
Mason Tang2bebde72010-08-04 17:20:24 -07001746 mCalendarOwnerAccount = "";
1747 if (mCalendarsCursor != null && mEventCursor != null) {
1748 mCalendarsCursor.moveToFirst();
1749 String tempAccount = mCalendarsCursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
1750 mCalendarOwnerAccount = (tempAccount == null) ? "" : tempAccount;
Michael Chan352e1a22010-09-28 05:15:08 -07001751 mOwnerCanRespond = mCalendarsCursor.getInt(CALENDARS_INDEX_OWNER_CAN_RESPOND) != 0;
Sara Ting42896f72012-03-15 15:24:36 -07001752 mSyncAccountName = mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_NAME);
Mason Tang2bebde72010-08-04 17:20:24 -07001753
Sara Ting6aad0ff2012-08-02 10:55:52 -07001754 // start visible calendars query
1755 mHandler.startQuery(TOKEN_QUERY_VISIBLE_CALENDARS, null, Calendars.CONTENT_URI,
1756 CALENDARS_PROJECTION, CALENDARS_VISIBLE_WHERE, new String[] {"1"}, null);
Mason Tang2bebde72010-08-04 17:20:24 -07001757
Michael Chan83efa2d2012-04-24 17:42:21 -07001758 mEventOrganizerEmail = mEventCursor.getString(EVENT_INDEX_ORGANIZER);
1759 mIsOrganizer = mCalendarOwnerAccount.equalsIgnoreCase(mEventOrganizerEmail);
1760
Sara Ting0c0da942012-04-27 10:35:05 -07001761 if (!TextUtils.isEmpty(mEventOrganizerEmail) &&
1762 !mEventOrganizerEmail.endsWith(Utils.MACHINE_GENERATED_ADDRESS)) {
Michael Chan83efa2d2012-04-24 17:42:21 -07001763 mEventOrganizerDisplayName = mEventOrganizerEmail;
1764 }
1765
1766 if (!mIsOrganizer && !TextUtils.isEmpty(mEventOrganizerDisplayName)) {
1767 setTextCommon(view, R.id.organizer, mEventOrganizerDisplayName);
Isaac Katzenelsonb7762cf2011-06-09 14:04:42 -07001768 setVisibilityCommon(view, R.id.organizer_container, View.VISIBLE);
1769 } else {
1770 setVisibilityCommon(view, R.id.organizer_container, View.GONE);
1771 }
Mason Tang2bebde72010-08-04 17:20:24 -07001772 mHasAttendeeData = mEventCursor.getInt(EVENT_INDEX_HAS_ATTENDEE_DATA) != 0;
RoboErik65eeb792011-08-08 12:54:00 -07001773 mCanModifyCalendar = mEventCursor.getInt(EVENT_INDEX_ACCESS_LEVEL)
1774 >= Calendars.CAL_ACCESS_CONTRIBUTOR;
1775 // TODO add "|| guestCanModify" after b/1299071 is fixed
1776 mCanModifyEvent = mCanModifyCalendar && mIsOrganizer;
Mason Tang2bebde72010-08-04 17:20:24 -07001777 mIsBusyFreeCalendar =
RoboErikef2add92011-06-09 14:49:53 -07001778 mEventCursor.getInt(EVENT_INDEX_ACCESS_LEVEL) == Calendars.CAL_ACCESS_FREEBUSY;
Michael Chan352e1a22010-09-28 05:15:08 -07001779
1780 if (!mIsBusyFreeCalendar) {
Isaac Katzenelsond4e45fa2012-06-04 16:38:11 -07001781
1782 View b = mView.findViewById(R.id.edit);
Michael Chan352e1a22010-09-28 05:15:08 -07001783 b.setEnabled(true);
Michael Chan8ce3b7d2010-09-01 15:41:01 -07001784 b.setOnClickListener(new OnClickListener() {
1785 @Override
1786 public void onClick(View v) {
1787 doEdit();
Isaac Katzenelson10b60212011-06-28 17:59:14 -07001788 // For dialogs, just close the fragment
1789 // For full screen, close activity on phone, leave it for tablet
Isaac Katzenelson60f01c22011-06-03 15:42:01 -07001790 if (mIsDialog) {
1791 EventInfoFragment.this.dismiss();
1792 }
Isaac Katzenelson10b60212011-06-28 17:59:14 -07001793 else if (!mIsTabletConfig){
Isaac Katzenelson60f01c22011-06-03 15:42:01 -07001794 getActivity().finish();
1795 }
Michael Chan352e1a22010-09-28 05:15:08 -07001796 }
1797 });
Michael Chan8ce3b7d2010-09-01 15:41:01 -07001798 }
Mindy Pereiradd151692011-08-29 14:05:26 -07001799 View button;
Sara Ting42896f72012-03-15 15:24:36 -07001800 if (mCanModifyCalendar) {
Mindy Pereiradd151692011-08-29 14:05:26 -07001801 button = mView.findViewById(R.id.delete);
1802 if (button != null) {
Sara Ting42896f72012-03-15 15:24:36 -07001803 button.setEnabled(true);
1804 button.setVisibility(View.VISIBLE);
RoboErik65eeb792011-08-08 12:54:00 -07001805 }
Mindy Pereiradd151692011-08-29 14:05:26 -07001806 }
Sara Ting42896f72012-03-15 15:24:36 -07001807 if (mCanModifyEvent) {
Mindy Pereiradd151692011-08-29 14:05:26 -07001808 button = mView.findViewById(R.id.edit);
1809 if (button != null) {
Sara Ting42896f72012-03-15 15:24:36 -07001810 button.setEnabled(true);
1811 button.setVisibility(View.VISIBLE);
Isaac Katzenelson60f01c22011-06-03 15:42:01 -07001812 }
RoboErikd8353fb2011-07-21 11:28:11 -07001813 }
Isaac Katzenelson7ef29812011-10-25 18:00:50 -07001814 if ((!mIsDialog && !mIsTabletConfig ||
1815 mWindowStyle == EventInfoFragment.FULL_WINDOW_STYLE) && mMenu != null) {
RoboErikd8353fb2011-07-21 11:28:11 -07001816 mActivity.invalidateOptionsMenu();
RoboErik69be8552011-02-14 16:51:59 -08001817 }
Mason Tang2bebde72010-08-04 17:20:24 -07001818 } else {
Michael Chan71b221a2010-10-25 17:55:44 -07001819 setVisibilityCommon(view, R.id.calendar, View.GONE);
Erik259b8f92011-01-12 14:01:12 -08001820 sendAccessibilityEventIfQueryDone(TOKEN_QUERY_DUPLICATE_CALENDARS);
Mason Tang2bebde72010-08-04 17:20:24 -07001821 }
1822 }
1823
RoboErikd8353fb2011-07-21 11:28:11 -07001824 /**
1825 *
1826 */
1827 private void updateMenu() {
1828 if (mMenu == null) {
1829 return;
1830 }
1831 MenuItem delete = mMenu.findItem(R.id.info_action_delete);
1832 MenuItem edit = mMenu.findItem(R.id.info_action_edit);
James Kung4afba182012-12-18 23:12:08 -08001833 MenuItem changeColor = mMenu.findItem(R.id.info_action_change_color);
RoboErikd8353fb2011-07-21 11:28:11 -07001834 if (delete != null) {
1835 delete.setVisible(mCanModifyCalendar);
1836 delete.setEnabled(mCanModifyCalendar);
1837 }
1838 if (edit != null) {
RoboErik65eeb792011-08-08 12:54:00 -07001839 edit.setVisible(mCanModifyEvent);
1840 edit.setEnabled(mCanModifyEvent);
RoboErikd8353fb2011-07-21 11:28:11 -07001841 }
James Kung4afba182012-12-18 23:12:08 -08001842 if (changeColor != null && mColors != null && mColors.length > 0) {
1843 changeColor.setVisible(mCanModifyCalendar);
1844 changeColor.setEnabled(mCanModifyCalendar);
1845 }
RoboErikd8353fb2011-07-21 11:28:11 -07001846 }
1847
Mason Tang2bebde72010-08-04 17:20:24 -07001848 private void updateAttendees(View view) {
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001849 if (mAcceptedAttendees.size() + mDeclinedAttendees.size() +
1850 mTentativeAttendees.size() + mNoResponseAttendees.size() > 0) {
RoboErikc7f3c382011-08-31 14:43:24 -07001851 mLongAttendees.clearAttendees();
RoboErik4acb2fd2011-07-18 15:39:49 -07001852 (mLongAttendees).addAttendees(mAcceptedAttendees);
1853 (mLongAttendees).addAttendees(mDeclinedAttendees);
1854 (mLongAttendees).addAttendees(mTentativeAttendees);
1855 (mLongAttendees).addAttendees(mNoResponseAttendees);
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001856 mLongAttendees.setEnabled(false);
1857 mLongAttendees.setVisibility(View.VISIBLE);
Isaac Katzenelson60f01c22011-06-03 15:42:01 -07001858 } else {
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001859 mLongAttendees.setVisibility(View.GONE);
Michael Chan71b221a2010-10-25 17:55:44 -07001860 }
Sara Tingcb5f5682012-04-04 22:52:20 -07001861
Sara Ting7ffa24c2012-08-28 15:44:37 -07001862 if (hasEmailableAttendees()) {
Sara Ting7da27672012-07-24 16:23:53 -07001863 setVisibilityCommon(mView, R.id.email_attendees_container, View.VISIBLE);
Sara Ting7ffa24c2012-08-28 15:44:37 -07001864 if (emailAttendeesButton != null) {
1865 emailAttendeesButton.setText(R.string.email_guests_label);
1866 }
1867 } else if (hasEmailableOrganizer()) {
1868 setVisibilityCommon(mView, R.id.email_attendees_container, View.VISIBLE);
1869 if (emailAttendeesButton != null) {
1870 emailAttendeesButton.setText(R.string.email_organizer_label);
1871 }
Sara Ting7da27672012-07-24 16:23:53 -07001872 } else {
1873 setVisibilityCommon(mView, R.id.email_attendees_container, View.GONE);
1874 }
Sara Tingcb5f5682012-04-04 22:52:20 -07001875 }
1876
1877 /**
Sara Ting7da27672012-07-24 16:23:53 -07001878 * Returns true if there is at least 1 attendee that is not the viewer.
Sara Tingcb5f5682012-04-04 22:52:20 -07001879 */
Sara Ting7ffa24c2012-08-28 15:44:37 -07001880 private boolean hasEmailableAttendees() {
Sara Tingcb5f5682012-04-04 22:52:20 -07001881 for (Attendee attendee : mAcceptedAttendees) {
Sara Ting7da27672012-07-24 16:23:53 -07001882 if (Utils.isEmailableFrom(attendee.mEmail, mSyncAccountName)) {
1883 return true;
1884 }
Sara Tingcb5f5682012-04-04 22:52:20 -07001885 }
1886 for (Attendee attendee : mTentativeAttendees) {
Sara Ting7da27672012-07-24 16:23:53 -07001887 if (Utils.isEmailableFrom(attendee.mEmail, mSyncAccountName)) {
1888 return true;
1889 }
Sara Tingcb5f5682012-04-04 22:52:20 -07001890 }
1891 for (Attendee attendee : mNoResponseAttendees) {
Sara Ting7da27672012-07-24 16:23:53 -07001892 if (Utils.isEmailableFrom(attendee.mEmail, mSyncAccountName)) {
1893 return true;
1894 }
Sara Tingcb5f5682012-04-04 22:52:20 -07001895 }
Sara Ting7da27672012-07-24 16:23:53 -07001896 for (Attendee attendee : mDeclinedAttendees) {
1897 if (Utils.isEmailableFrom(attendee.mEmail, mSyncAccountName)) {
1898 return true;
1899 }
Sara Tingcb5f5682012-04-04 22:52:20 -07001900 }
Sara Ting7ffa24c2012-08-28 15:44:37 -07001901 return false;
1902 }
1903
1904 private boolean hasEmailableOrganizer() {
Sara Ting7da27672012-07-24 16:23:53 -07001905 return mEventOrganizerEmail != null &&
1906 Utils.isEmailableFrom(mEventOrganizerEmail, mSyncAccountName);
Michael Chan8ce3b7d2010-09-01 15:41:01 -07001907 }
1908
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001909 public void initReminders(View view, Cursor cursor) {
1910
1911 // Add reminders
RoboErikc7f3c382011-08-31 14:43:24 -07001912 mOriginalReminders.clear();
RoboErikc08957b2011-09-09 13:43:38 -07001913 mUnsupportedReminders.clear();
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001914 while (cursor.moveToNext()) {
1915 int minutes = cursor.getInt(EditEventHelper.REMINDERS_INDEX_MINUTES);
1916 int method = cursor.getInt(EditEventHelper.REMINDERS_INDEX_METHOD);
RoboErike35a0322011-09-01 16:21:49 -07001917
RoboErikc08957b2011-09-09 13:43:38 -07001918 if (method != Reminders.METHOD_DEFAULT && !mReminderMethodValues.contains(method)) {
RoboErike35a0322011-09-01 16:21:49 -07001919 // Stash unsupported reminder types separately so we don't alter
1920 // them in the UI
1921 mUnsupportedReminders.add(ReminderEntry.valueOf(minutes, method));
1922 } else {
1923 mOriginalReminders.add(ReminderEntry.valueOf(minutes, method));
1924 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001925 }
1926 // Sort appropriately for display (by time, then type)
1927 Collections.sort(mOriginalReminders);
1928
RoboErik8b5743c2011-09-27 16:07:09 -07001929 if (mUserModifiedReminders) {
1930 // If the user has changed the list of reminders don't change what's
1931 // shown.
1932 return;
1933 }
1934
RoboErik5d40a382011-09-02 14:33:09 -07001935 LinearLayout parent = (LinearLayout) mScrollView
1936 .findViewById(R.id.reminder_items_container);
1937 if (parent != null) {
1938 parent.removeAllViews();
1939 }
RoboErikc08957b2011-09-09 13:43:38 -07001940 if (mReminderViews != null) {
1941 mReminderViews.clear();
1942 }
RoboErik5d40a382011-09-02 14:33:09 -07001943
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001944 if (mHasAlarm) {
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -08001945 ArrayList<ReminderEntry> reminders;
1946 // If applicable, use reminders saved in the bundle.
1947 if (mReminders != null) {
1948 reminders = mReminders;
1949 } else {
1950 reminders = mOriginalReminders;
1951 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001952 // Insert any minute values that aren't represented in the minutes list.
1953 for (ReminderEntry re : reminders) {
1954 EventViewUtils.addMinutesToList(
1955 mActivity, mReminderMinuteValues, mReminderMinuteLabels, re.getMinutes());
1956 }
1957 // Create a UI element for each reminder. We display all of the reminders we get
1958 // from the provider, even if the count exceeds the calendar maximum. (Also, for
1959 // a new event, we won't have a maxReminders value available.)
1960 for (ReminderEntry re : reminders) {
RoboErike35a0322011-09-01 16:21:49 -07001961 EventViewUtils.addReminder(mActivity, mScrollView, this, mReminderViews,
1962 mReminderMinuteValues, mReminderMinuteLabels, mReminderMethodValues,
RoboErik8b5743c2011-09-27 16:07:09 -07001963 mReminderMethodLabels, re, Integer.MAX_VALUE, mReminderChangeListener);
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001964 }
Sara Ting06f3d6d2012-03-23 17:19:22 -07001965 EventViewUtils.updateAddReminderButton(mView, mReminderViews, mMaxReminders);
RoboErike35a0322011-09-01 16:21:49 -07001966 // TODO show unsupported reminder types in some fashion.
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001967 }
1968 }
1969
Mason Tang2bebde72010-08-04 17:20:24 -07001970 void updateResponse(View view) {
1971 // we only let the user accept/reject/etc. a meeting if:
1972 // a) you can edit the event's containing calendar AND
1973 // b) you're not the organizer and only attendee AND
1974 // c) organizerCanRespond is enabled for the calendar
1975 // (if the attendee data has been hidden, the visible number of attendees
1976 // will be 1 -- the calendar owner's).
1977 // (there are more cases involved to be 100% accurate, such as
1978 // paying attention to whether or not an attendee status was
1979 // included in the feed, but we're currently omitting those corner cases
1980 // for simplicity).
Michael Chan352e1a22010-09-28 05:15:08 -07001981
1982 // TODO Switch to EditEventHelper.canRespond when this class uses CalendarEventModel.
Michael Chand785cd52010-09-03 13:57:19 -07001983 if (!mCanModifyCalendar || (mHasAttendeeData && mIsOrganizer && mNumOfAttendees <= 1) ||
Michael Chan352e1a22010-09-28 05:15:08 -07001984 (mIsOrganizer && !mOwnerCanRespond)) {
Mason Tang2bebde72010-08-04 17:20:24 -07001985 setVisibilityCommon(view, R.id.response_container, View.GONE);
1986 return;
1987 }
1988
1989 setVisibilityCommon(view, R.id.response_container, View.VISIBLE);
1990
Mason Tang2bebde72010-08-04 17:20:24 -07001991
Michael Chanf92f46b2010-10-27 18:59:05 -07001992 int response;
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08001993 if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
1994 response = mTentativeUserSetResponse;
1995 } else if (mUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
RoboErik5afc0832011-09-27 14:14:09 -07001996 response = mUserSetResponse;
Isaac Katzenelson6bcafcf2012-05-02 18:25:36 -07001997 } else if (mAttendeeResponseFromIntent != Attendees.ATTENDEE_STATUS_NONE) {
Michael Chanf92f46b2010-10-27 18:59:05 -07001998 response = mAttendeeResponseFromIntent;
Mason Tang2bebde72010-08-04 17:20:24 -07001999 } else {
Michael Chanf92f46b2010-10-27 18:59:05 -07002000 response = mOriginalAttendeeResponse;
Mason Tang2bebde72010-08-04 17:20:24 -07002001 }
Michael Chanf92f46b2010-10-27 18:59:05 -07002002
2003 int buttonToCheck = findButtonIdForResponse(response);
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08002004 mResponseRadioGroup.check(buttonToCheck); // -1 clear all radio buttons
2005 mResponseRadioGroup.setOnCheckedChangeListener(this);
Mason Tang2bebde72010-08-04 17:20:24 -07002006 }
2007
2008 private void setTextCommon(View view, int id, CharSequence text) {
2009 TextView textView = (TextView) view.findViewById(id);
2010 if (textView == null)
2011 return;
2012 textView.setText(text);
2013 }
2014
2015 private void setVisibilityCommon(View view, int id, int visibility) {
2016 View v = view.findViewById(id);
2017 if (v != null) {
2018 v.setVisibility(visibility);
2019 }
2020 return;
2021 }
2022
2023 /**
2024 * Taken from com.google.android.gm.HtmlConversationActivity
2025 *
2026 * Send the intent that shows the Contact info corresponding to the email address.
2027 */
2028 public void showContactInfo(Attendee attendee, Rect rect) {
2029 // First perform lookup query to find existing contact
2030 final ContentResolver resolver = getActivity().getContentResolver();
2031 final String address = attendee.mEmail;
2032 final Uri dataUri = Uri.withAppendedPath(CommonDataKinds.Email.CONTENT_FILTER_URI,
2033 Uri.encode(address));
2034 final Uri lookupUri = ContactsContract.Data.getContactLookupUri(resolver, dataUri);
2035
2036 if (lookupUri != null) {
2037 // Found matching contact, trigger QuickContact
2038 QuickContact.showQuickContact(getActivity(), rect, lookupUri,
2039 QuickContact.MODE_MEDIUM, null);
2040 } else {
2041 // No matching contact, ask user to create one
2042 final Uri mailUri = Uri.fromParts("mailto", address, null);
2043 final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, mailUri);
2044
2045 // Pass along full E-mail string for possible create dialog
2046 Rfc822Token sender = new Rfc822Token(attendee.mName, attendee.mEmail, null);
2047 intent.putExtra(Intents.EXTRA_CREATE_DESCRIPTION, sender.toString());
2048
2049 // Only provide personal name hint if we have one
2050 final String senderPersonal = attendee.mName;
2051 if (!TextUtils.isEmpty(senderPersonal)) {
2052 intent.putExtra(Intents.Insert.NAME, senderPersonal);
2053 }
2054
2055 startActivity(intent);
2056 }
2057 }
Erikcb811892010-09-28 13:44:19 -07002058
2059 @Override
RoboErik7c6236d2011-02-24 16:41:18 -08002060 public void onPause() {
2061 mIsPaused = true;
2062 mHandler.removeCallbacks(onDeleteRunnable);
2063 super.onPause();
Isaac Katzenelsonb0a313a2011-10-24 11:41:56 -07002064 // Remove event deletion alert box since it is being rebuild in the OnResume
2065 // This is done to get the same behavior on OnResume since the AlertDialog is gone on
2066 // rotation but not if you press the HOME key
2067 if (mDeleteDialogVisible && mDeleteHelper != null) {
2068 mDeleteHelper.dismissAlertDialog();
2069 mDeleteHelper = null;
2070 }
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08002071 if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE
2072 && mEditResponseHelper != null) {
2073 mEditResponseHelper.dismissAlertDialog();
2074 }
RoboErik7c6236d2011-02-24 16:41:18 -08002075 }
2076
2077 @Override
2078 public void onResume() {
2079 super.onResume();
Michael Chan363aa9c2012-05-17 10:31:32 -07002080 if (mIsDialog) {
2081 setDialogSize(getActivity().getResources());
2082 applyDialogParams();
2083 }
RoboErik7c6236d2011-02-24 16:41:18 -08002084 mIsPaused = false;
2085 if (mDismissOnResume) {
2086 mHandler.post(onDeleteRunnable);
2087 }
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08002088 // Display the "delete confirmation" or "edit response helper" dialog if needed
Isaac Katzenelsonb0a313a2011-10-24 11:41:56 -07002089 if (mDeleteDialogVisible) {
2090 mDeleteHelper = new DeleteEventHelper(
2091 mContext, mActivity,
2092 !mIsDialog && !mIsTabletConfig /* exitWhenDone */);
2093 mDeleteHelper.setOnDismissListener(createDeleteOnDismissListener());
2094 mDeleteHelper.delete(mStartMillis, mEndMillis, mEventId, -1, onDeleteRunnable);
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08002095 } else if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
2096 int buttonId = findButtonIdForResponse(mTentativeUserSetResponse);
2097 mResponseRadioGroup.check(buttonId);
2098 mEditResponseHelper.showDialog(mEditResponseHelper.getWhichEvents());
Isaac Katzenelsonb0a313a2011-10-24 11:41:56 -07002099 }
RoboErik7c6236d2011-02-24 16:41:18 -08002100 }
2101
2102 @Override
Erikcb811892010-09-28 13:44:19 -07002103 public void eventsChanged() {
2104 }
2105
2106 @Override
Erikcb811892010-09-28 13:44:19 -07002107 public long getSupportedEventTypes() {
2108 return EventType.EVENTS_CHANGED;
2109 }
2110
2111 @Override
Erikcb811892010-09-28 13:44:19 -07002112 public void handleEvent(EventInfo event) {
James Kung4afba182012-12-18 23:12:08 -08002113 reloadEvents();
Erikcb811892010-09-28 13:44:19 -07002114 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002115
Isaac Katzenelson80d640f2012-04-20 09:21:28 -07002116 public void reloadEvents() {
James Kung4afba182012-12-18 23:12:08 -08002117 if (mHandler != null) {
2118 mHandler.startQuery(TOKEN_QUERY_EVENT, null, mUri, EVENT_PROJECTION,
2119 null, null, null);
2120 }
Isaac Katzenelson80d640f2012-04-20 09:21:28 -07002121 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002122
2123 @Override
2124 public void onClick(View view) {
2125
2126 // This must be a click on one of the "remove reminder" buttons
2127 LinearLayout reminderItem = (LinearLayout) view.getParent();
2128 LinearLayout parent = (LinearLayout) reminderItem.getParent();
2129 parent.removeView(reminderItem);
2130 mReminderViews.remove(reminderItem);
RoboErik8b5743c2011-09-27 16:07:09 -07002131 mUserModifiedReminders = true;
Sara Ting06f3d6d2012-03-23 17:19:22 -07002132 EventViewUtils.updateAddReminderButton(mView, mReminderViews, mMaxReminders);
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002133 }
2134
2135
2136 /**
2137 * Add a new reminder when the user hits the "add reminder" button. We use the default
2138 * reminder time and method.
2139 */
2140 private void addReminder() {
2141 // TODO: when adding a new reminder, make it different from the
2142 // last one in the list (if any).
2143 if (mDefaultReminderMinutes == GeneralPreferences.NO_REMINDER) {
2144 EventViewUtils.addReminder(mActivity, mScrollView, this, mReminderViews,
RoboErik8b5743c2011-09-27 16:07:09 -07002145 mReminderMinuteValues, mReminderMinuteLabels, mReminderMethodValues,
2146 mReminderMethodLabels,
2147 ReminderEntry.valueOf(GeneralPreferences.REMINDER_DEFAULT_TIME), mMaxReminders,
2148 mReminderChangeListener);
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002149 } else {
2150 EventViewUtils.addReminder(mActivity, mScrollView, this, mReminderViews,
RoboErik8b5743c2011-09-27 16:07:09 -07002151 mReminderMinuteValues, mReminderMinuteLabels, mReminderMethodValues,
2152 mReminderMethodLabels, ReminderEntry.valueOf(mDefaultReminderMinutes),
2153 mMaxReminders, mReminderChangeListener);
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002154 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002155
Sara Ting06f3d6d2012-03-23 17:19:22 -07002156 EventViewUtils.updateAddReminderButton(mView, mReminderViews, mMaxReminders);
2157 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002158
RoboErike35a0322011-09-01 16:21:49 -07002159 synchronized private void prepareReminders() {
2160 // Nothing to do if we've already built these lists _and_ we aren't
2161 // removing not allowed methods
2162 if (mReminderMinuteValues != null && mReminderMinuteLabels != null
2163 && mReminderMethodValues != null && mReminderMethodLabels != null
2164 && mCalendarAllowedReminders == null) {
2165 return;
2166 }
2167 // Load the labels and corresponding numeric values for the minutes and methods lists
2168 // from the assets. If we're switching calendars, we need to clear and re-populate the
2169 // lists (which may have elements added and removed based on calendar properties). This
2170 // is mostly relevant for "methods", since we shouldn't have any "minutes" values in a
2171 // new event that aren't in the default set.
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002172 Resources r = mActivity.getResources();
2173 mReminderMinuteValues = loadIntegerArray(r, R.array.reminder_minutes_values);
2174 mReminderMinuteLabels = loadStringArray(r, R.array.reminder_minutes_labels);
2175 mReminderMethodValues = loadIntegerArray(r, R.array.reminder_methods_values);
2176 mReminderMethodLabels = loadStringArray(r, R.array.reminder_methods_labels);
RoboErike35a0322011-09-01 16:21:49 -07002177
2178 // Remove any reminder methods that aren't allowed for this calendar. If this is
2179 // a new event, mCalendarAllowedReminders may not be set the first time we're called.
RoboErike35a0322011-09-01 16:21:49 -07002180 if (mCalendarAllowedReminders != null) {
2181 EventViewUtils.reduceMethodList(mReminderMethodValues, mReminderMethodLabels,
2182 mCalendarAllowedReminders);
2183 }
2184 if (mView != null) {
2185 mView.invalidate();
2186 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002187 }
2188
2189
2190 private boolean saveReminders() {
2191 ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(3);
2192
2193 // Read reminders from UI
2194 mReminders = EventViewUtils.reminderItemsToReminders(mReminderViews,
2195 mReminderMinuteValues, mReminderMethodValues);
RoboErike35a0322011-09-01 16:21:49 -07002196 mOriginalReminders.addAll(mUnsupportedReminders);
2197 Collections.sort(mOriginalReminders);
2198 mReminders.addAll(mUnsupportedReminders);
2199 Collections.sort(mReminders);
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002200
2201 // Check if there are any changes in the reminder
2202 boolean changed = EditEventHelper.saveReminders(ops, mEventId, mReminders,
2203 mOriginalReminders, false /* no force save */);
2204
2205 if (!changed) {
2206 return false;
2207 }
2208
2209 // save new reminders
2210 AsyncQueryService service = new AsyncQueryService(getActivity());
2211 service.startBatch(0, null, Calendars.CONTENT_URI.getAuthority(), ops, 0);
Sam Blitzstein9d4a9522012-10-17 14:39:38 -07002212 mOriginalReminders = mReminders;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002213 // Update the "hasAlarm" field for the event
2214 Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId);
2215 int len = mReminders.size();
2216 boolean hasAlarm = len > 0;
2217 if (hasAlarm != mHasAlarm) {
2218 ContentValues values = new ContentValues();
2219 values.put(Events.HAS_ALARM, hasAlarm ? 1 : 0);
2220 service.startUpdate(0, null, uri, values, null, null, 0);
2221 }
2222 return true;
2223 }
2224
2225 /**
Sara Ting42896f72012-03-15 15:24:36 -07002226 * Email all the attendees of the event, except for the viewer (so as to not email
2227 * himself) and resources like conference rooms.
2228 */
2229 private void emailAttendees() {
Sara Ting7da27672012-07-24 16:23:53 -07002230 Intent i = new Intent(getActivity(), QuickResponseActivity.class);
2231 i.putExtra(QuickResponseActivity.EXTRA_EVENT_ID, mEventId);
2232 i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2233 startActivity(i);
Sara Ting42896f72012-03-15 15:24:36 -07002234 }
2235
2236 /**
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002237 * Loads an integer array asset into a list.
2238 */
2239 private static ArrayList<Integer> loadIntegerArray(Resources r, int resNum) {
2240 int[] vals = r.getIntArray(resNum);
2241 int size = vals.length;
2242 ArrayList<Integer> list = new ArrayList<Integer>(size);
2243
2244 for (int i = 0; i < size; i++) {
2245 list.add(vals[i]);
2246 }
2247
2248 return list;
2249 }
2250 /**
2251 * Loads a String array asset into a list.
2252 */
2253 private static ArrayList<String> loadStringArray(Resources r, int resNum) {
2254 String[] labels = r.getStringArray(resNum);
2255 ArrayList<String> list = new ArrayList<String>(Arrays.asList(labels));
2256 return list;
2257 }
2258
Michael Chan48bcc4c2012-12-12 11:38:16 -08002259 @Override
Isaac Katzenelsonb33cdf42011-10-14 18:15:18 -07002260 public void onDeleteStarted() {
2261 mEventDeletionStarted = true;
2262 }
2263
Isaac Katzenelsonb0a313a2011-10-24 11:41:56 -07002264 private Dialog.OnDismissListener createDeleteOnDismissListener() {
2265 return new Dialog.OnDismissListener() {
2266 @Override
2267 public void onDismiss(DialogInterface dialog) {
2268 // Since OnPause will force the dialog to dismiss , do
2269 // not change the dialog status
2270 if (!mIsPaused) {
2271 mDeleteDialogVisible = false;
2272 }
2273 }
2274 };
2275 }
2276
Isaac Katzenelson80d640f2012-04-20 09:21:28 -07002277 public long getEventId() {
2278 return mEventId;
2279 }
2280
2281 public long getStartMillis() {
2282 return mStartMillis;
2283 }
2284 public long getEndMillis() {
2285 return mEndMillis;
2286 }
Michael Chan363aa9c2012-05-17 10:31:32 -07002287 private void setDialogSize(Resources r) {
2288 mDialogWidth = (int)r.getDimension(R.dimen.event_info_dialog_width);
2289 mDialogHeight = (int)r.getDimension(R.dimen.event_info_dialog_height);
2290 }
James Kungb8904fb2013-02-14 14:37:42 -08002291
2292 @Override
2293 public void onColorSelected(int color) {
James Kung497a6252013-05-17 14:47:33 -07002294 mCurrentColor = color;
2295 mCurrentColorKey = mDisplayColorKeyMap.get(color);
2296 mHeadlines.setBackgroundColor(color);
James Kungb8904fb2013-02-14 14:37:42 -08002297 }
Mason Tang2bebde72010-08-04 17:20:24 -07002298}