blob: 10436cf57b16d69cc25ce2e8293a3bc790fbbed7 [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;
361 private ObjectAnimator mAnimateAlpha;
Isaac Katzenelson263b0292012-03-14 14:55:50 -0700362 private long mLoadingMsgStartTime;
James Kung4afba182012-12-18 23:12:08 -0800363
James Kung2fca0242013-04-02 16:09:50 -0700364 private EventColorPickerDialog mColorPickerDialog;
James Kunge134cd52013-02-13 11:33:49 -0800365 private SparseIntArray mDisplayColorKeyMap = new SparseIntArray();
James Kung4afba182012-12-18 23:12:08 -0800366 private int[] mColors;
367 private int mOriginalColor = -1;
James Kungf56b1492013-03-07 15:10:13 -0800368 private boolean mOriginalColorInitialized = false;
James Kung4afba182012-12-18 23:12:08 -0800369 private int mCalendarColor = -1;
James Kungf56b1492013-03-07 15:10:13 -0800370 private boolean mCalendarColorInitialized = false;
James Kung4afba182012-12-18 23:12:08 -0800371 private int mCurrentColor = -1;
James Kungf56b1492013-03-07 15:10:13 -0800372 private boolean mCurrentColorInitialized = false;
James Kung497a6252013-05-17 14:47:33 -0700373 private int mCurrentColorKey = -1;
James Kung4afba182012-12-18 23:12:08 -0800374
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800375 private static final int FADE_IN_TIME = 300; // in milliseconds
Isaac Katzenelson263b0292012-03-14 14:55:50 -0700376 private static final int LOADING_MSG_DELAY = 600; // in milliseconds
377 private static final int LOADING_MSG_MIN_DISPLAY_TIME = 600;
Isaac Katzenelson80d640f2012-04-20 09:21:28 -0700378 private boolean mNoCrossFade = false; // Used to prevent repeated cross-fade
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800379 private RadioGroup mResponseRadioGroup;
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800380
Mason Tang2bebde72010-08-04 17:20:24 -0700381 ArrayList<Attendee> mAcceptedAttendees = new ArrayList<Attendee>();
382 ArrayList<Attendee> mDeclinedAttendees = new ArrayList<Attendee>();
383 ArrayList<Attendee> mTentativeAttendees = new ArrayList<Attendee>();
384 ArrayList<Attendee> mNoResponseAttendees = new ArrayList<Attendee>();
Sara Tingcb5f5682012-04-04 22:52:20 -0700385 ArrayList<String> mToEmails = new ArrayList<String>();
386 ArrayList<String> mCcEmails = new ArrayList<String>();
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700387
388 private int mDefaultReminderMinutes;
Isaac Katzenelsonac4350b2012-04-18 15:33:26 -0700389 private final ArrayList<LinearLayout> mReminderViews = new ArrayList<LinearLayout>(0);
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700390 public ArrayList<ReminderEntry> mReminders;
RoboErik7f078b72011-09-06 10:25:31 -0700391 public ArrayList<ReminderEntry> mOriginalReminders = new ArrayList<ReminderEntry>();
392 public ArrayList<ReminderEntry> mUnsupportedReminders = new ArrayList<ReminderEntry>();
RoboErik8b5743c2011-09-27 16:07:09 -0700393 private boolean mUserModifiedReminders = false;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700394
395 /**
396 * Contents of the "minutes" spinner. This has default values from the XML file, augmented
397 * with any additional values that were already associated with the event.
398 */
399 private ArrayList<Integer> mReminderMinuteValues;
400 private ArrayList<String> mReminderMinuteLabels;
401
402 /**
403 * Contents of the "methods" spinner. The "values" list specifies the method constant
404 * (e.g. {@link Reminders#METHOD_ALERT}) associated with the labels. Any methods that
405 * aren't allowed by the Calendar will be removed.
406 */
407 private ArrayList<Integer> mReminderMethodValues;
408 private ArrayList<String> mReminderMethodLabels;
409
Mason Tang2bebde72010-08-04 17:20:24 -0700410 private QueryHandler mHandler;
411
Isaac Katzenelsonb33cdf42011-10-14 18:15:18 -0700412
Isaac Katzenelsonac4350b2012-04-18 15:33:26 -0700413 private final Runnable mTZUpdater = new Runnable() {
Erikcb811892010-09-28 13:44:19 -0700414 @Override
415 public void run() {
416 updateEvent(mView);
417 }
418 };
419
Isaac Katzenelsonac4350b2012-04-18 15:33:26 -0700420 private final Runnable mLoadingMsgAlphaUpdater = new Runnable() {
Isaac Katzenelson263b0292012-03-14 14:55:50 -0700421 @Override
422 public void run() {
423 // Since this is run after a delay, make sure to only show the message
424 // if the event's data is not shown yet.
425 if (!mAnimateAlpha.isRunning() && mScrollView.getAlpha() == 0) {
426 mLoadingMsgStartTime = System.currentTimeMillis();
427 mLoadingMsgView.setAlpha(1);
428 }
429 }
430 };
431
RoboErik8b5743c2011-09-27 16:07:09 -0700432 private OnItemSelectedListener mReminderChangeListener;
433
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700434 private static int mDialogWidth = 500;
435 private static int mDialogHeight = 600;
Isaac Katzenelson0aa0c612011-10-03 16:46:10 -0700436 private static int DIALOG_TOP_MARGIN = 8;
Michael Chan71d08832010-08-25 18:28:59 -0700437 private boolean mIsDialog = false;
RoboErik7c6236d2011-02-24 16:41:18 -0800438 private boolean mIsPaused = true;
439 private boolean mDismissOnResume = false;
Michael Chan71d08832010-08-25 18:28:59 -0700440 private int mX = -1;
441 private int mY = -1;
Isaac Katzenelson0aa0c612011-10-03 16:46:10 -0700442 private int mMinTop; // Dialog cannot be above this location
Isaac Katzenelson10b60212011-06-28 17:59:14 -0700443 private boolean mIsTabletConfig;
444 private Activity mActivity;
Michael Chanbe2a4322011-08-11 13:39:14 -0700445 private Context mContext;
Michael Chan71d08832010-08-25 18:28:59 -0700446
James Kung4afba182012-12-18 23:12:08 -0800447 private CalendarController mController;
448
Mason Tang2bebde72010-08-04 17:20:24 -0700449 private class QueryHandler extends AsyncQueryService {
450 public QueryHandler(Context context) {
451 super(context);
452 }
453
454 @Override
455 protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
Mason Tang4003d1c2010-08-17 13:50:45 -0700456 // if the activity is finishing, then close the cursor and return
457 final Activity activity = getActivity();
458 if (activity == null || activity.isFinishing()) {
Isaac Katzenelson47f6cc62012-06-28 18:56:16 -0700459 if (cursor != null) {
460 cursor.close();
461 }
Mason Tang4003d1c2010-08-17 13:50:45 -0700462 return;
463 }
464
Mason Tang2bebde72010-08-04 17:20:24 -0700465 switch (token) {
466 case TOKEN_QUERY_EVENT:
467 mEventCursor = Utils.matrixCursorFromCursor(cursor);
468 if (initEventCursor()) {
469 // The cursor is empty. This can happen if the event was
470 // deleted.
471 // FRAG_TODO we should no longer rely on Activity.finish()
Mason Tang1df2ca62010-08-18 16:10:25 -0700472 activity.finish();
Mason Tang2bebde72010-08-04 17:20:24 -0700473 return;
474 }
James Kungf56b1492013-03-07 15:10:13 -0800475 if (!mCalendarColorInitialized) {
James Kung4afba182012-12-18 23:12:08 -0800476 mCalendarColor = Utils.getDisplayColorFromColor(
477 mEventCursor.getInt(EVENT_INDEX_CALENDAR_COLOR));
James Kungf56b1492013-03-07 15:10:13 -0800478 mCalendarColorInitialized = true;
James Kung4afba182012-12-18 23:12:08 -0800479 }
480
James Kungf56b1492013-03-07 15:10:13 -0800481 if (!mOriginalColorInitialized) {
James Kung4afba182012-12-18 23:12:08 -0800482 mOriginalColor = mEventCursor.isNull(EVENT_INDEX_EVENT_COLOR)
483 ? mCalendarColor : Utils.getDisplayColorFromColor(
484 mEventCursor.getInt(EVENT_INDEX_EVENT_COLOR));
James Kungf56b1492013-03-07 15:10:13 -0800485 mOriginalColorInitialized = true;
James Kung4afba182012-12-18 23:12:08 -0800486 }
487
James Kungf56b1492013-03-07 15:10:13 -0800488 if (!mCurrentColorInitialized) {
James Kung4afba182012-12-18 23:12:08 -0800489 mCurrentColor = mOriginalColor;
James Kungf56b1492013-03-07 15:10:13 -0800490 mCurrentColorInitialized = true;
James Kung4afba182012-12-18 23:12:08 -0800491 }
492
Mason Tang2bebde72010-08-04 17:20:24 -0700493 updateEvent(mView);
RoboErike35a0322011-09-01 16:21:49 -0700494 prepareReminders();
Mason Tang2bebde72010-08-04 17:20:24 -0700495
496 // start calendar query
497 Uri uri = Calendars.CONTENT_URI;
498 String[] args = new String[] {
499 Long.toString(mEventCursor.getLong(EVENT_INDEX_CALENDAR_ID))};
500 startQuery(TOKEN_QUERY_CALENDARS, null, uri, CALENDARS_PROJECTION,
501 CALENDARS_WHERE, args, null);
502 break;
503 case TOKEN_QUERY_CALENDARS:
504 mCalendarsCursor = Utils.matrixCursorFromCursor(cursor);
505 updateCalendar(mView);
Mason Tang4003d1c2010-08-17 13:50:45 -0700506 // FRAG_TODO fragments shouldn't set the title anymore
Mason Tang2bebde72010-08-04 17:20:24 -0700507 updateTitle();
508
James Kung4afba182012-12-18 23:12:08 -0800509 args = new String[] {
510 mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_NAME),
511 mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_TYPE) };
512 uri = Colors.CONTENT_URI;
513 startQuery(TOKEN_QUERY_COLORS, null, uri, COLORS_PROJECTION, COLORS_WHERE, args,
514 null);
515
Michael Chan352e1a22010-09-28 05:15:08 -0700516 if (!mIsBusyFreeCalendar) {
Michael Chan352e1a22010-09-28 05:15:08 -0700517 args = new String[] { Long.toString(mEventId) };
Mason Tang2bebde72010-08-04 17:20:24 -0700518
Michael Chan352e1a22010-09-28 05:15:08 -0700519 // start attendees query
520 uri = Attendees.CONTENT_URI;
521 startQuery(TOKEN_QUERY_ATTENDEES, null, uri, ATTENDEES_PROJECTION,
522 ATTENDEES_WHERE, args, ATTENDEES_SORT_ORDER);
Erik259b8f92011-01-12 14:01:12 -0800523 } else {
524 sendAccessibilityEventIfQueryDone(TOKEN_QUERY_ATTENDEES);
Mason Tang2bebde72010-08-04 17:20:24 -0700525 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700526 if (mHasAlarm) {
527 // start reminders query
528 args = new String[] { Long.toString(mEventId) };
529 uri = Reminders.CONTENT_URI;
530 startQuery(TOKEN_QUERY_REMINDERS, null, uri,
531 REMINDERS_PROJECTION, REMINDERS_WHERE, args, null);
532 } else {
533 sendAccessibilityEventIfQueryDone(TOKEN_QUERY_REMINDERS);
534 }
Mason Tang2bebde72010-08-04 17:20:24 -0700535 break;
James Kung4afba182012-12-18 23:12:08 -0800536 case TOKEN_QUERY_COLORS:
537 ArrayList<Integer> colors = new ArrayList<Integer>();
538 if (cursor.moveToFirst()) {
539 do
540 {
541 int colorKey = cursor.getInt(COLORS_INDEX_COLOR_KEY);
542 int rawColor = cursor.getInt(COLORS_INDEX_COLOR);
543 int displayColor = Utils.getDisplayColorFromColor(rawColor);
James Kunge134cd52013-02-13 11:33:49 -0800544 mDisplayColorKeyMap.put(displayColor, colorKey);
James Kung4afba182012-12-18 23:12:08 -0800545 colors.add(displayColor);
546 } while (cursor.moveToNext());
547 }
548 cursor.close();
549 Integer[] sortedColors = new Integer[colors.size()];
James Kunge134cd52013-02-13 11:33:49 -0800550 Arrays.sort(colors.toArray(sortedColors), new HsvColorComparator());
James Kung4afba182012-12-18 23:12:08 -0800551 mColors = new int[sortedColors.length];
552 for (int i = 0; i < sortedColors.length; i++) {
553 mColors[i] = sortedColors[i].intValue();
554
555 float[] hsv = new float[3];
556 Color.colorToHSV(mColors[i], hsv);
James Kunge134cd52013-02-13 11:33:49 -0800557 if (DEBUG) {
558 Log.d("Color", "H:" + hsv[0] + ",S:" + hsv[1] + ",V:" + hsv[2]);
559 }
James Kung4afba182012-12-18 23:12:08 -0800560 }
James Kung6090ba22013-04-03 13:00:49 -0700561 if (mCanModifyCalendar) {
562 View button = mView.findViewById(R.id.change_color);
563 if (button != null && mColors.length > 0) {
564 button.setEnabled(true);
565 button.setVisibility(View.VISIBLE);
566 }
James Kung4afba182012-12-18 23:12:08 -0800567 }
568 updateMenu();
James Kung4afba182012-12-18 23:12:08 -0800569 break;
Mason Tang2bebde72010-08-04 17:20:24 -0700570 case TOKEN_QUERY_ATTENDEES:
571 mAttendeesCursor = Utils.matrixCursorFromCursor(cursor);
572 initAttendeesCursor(mView);
573 updateResponse(mView);
574 break;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700575 case TOKEN_QUERY_REMINDERS:
576 mRemindersCursor = Utils.matrixCursorFromCursor(cursor);
577 initReminders(mView, mRemindersCursor);
578 break;
Sara Ting6aad0ff2012-08-02 10:55:52 -0700579 case TOKEN_QUERY_VISIBLE_CALENDARS:
580 if (cursor.getCount() > 1) {
581 // Start duplicate calendars query to detect whether to add the calendar
582 // email to the calendar owner display.
583 String displayName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
584 mHandler.startQuery(TOKEN_QUERY_DUPLICATE_CALENDARS, null,
585 Calendars.CONTENT_URI, CALENDARS_PROJECTION,
586 CALENDARS_DUPLICATE_NAME_WHERE, new String[] {displayName}, null);
587 } else {
588 // Don't need to display the calendar owner when there is only a single
589 // calendar. Skip the duplicate calendars query.
590 setVisibilityCommon(mView, R.id.calendar_container, View.GONE);
591 mCurrentQuery |= TOKEN_QUERY_DUPLICATE_CALENDARS;
592 }
593 break;
Mason Tang2bebde72010-08-04 17:20:24 -0700594 case TOKEN_QUERY_DUPLICATE_CALENDARS:
Michael Chan71b221a2010-10-25 17:55:44 -0700595 SpannableStringBuilder sb = new SpannableStringBuilder();
596
Michael Chan71b221a2010-10-25 17:55:44 -0700597 // Calendar display name
Mason Tang2bebde72010-08-04 17:20:24 -0700598 String calendarName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
Michael Chan71b221a2010-10-25 17:55:44 -0700599 sb.append(calendarName);
600
601 // Show email account if display name is not unique and
602 // display name != email
603 String email = mCalendarsCursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
Sara Ting6aad0ff2012-08-02 10:55:52 -0700604 if (cursor.getCount() > 1 && !calendarName.equalsIgnoreCase(email) &&
605 Utils.isValidEmail(email)) {
Michael Chan71b221a2010-10-25 17:55:44 -0700606 sb.append(" (").append(email).append(")");
607 }
608
Sara Ting6aad0ff2012-08-02 10:55:52 -0700609 setVisibilityCommon(mView, R.id.calendar_container, View.VISIBLE);
610 setTextCommon(mView, R.id.calendar_name, sb);
Mason Tang2bebde72010-08-04 17:20:24 -0700611 break;
612 }
613 cursor.close();
Erik259b8f92011-01-12 14:01:12 -0800614 sendAccessibilityEventIfQueryDone(token);
Sara Ting6aad0ff2012-08-02 10:55:52 -0700615
616 // All queries are done, show the view.
Isaac Katzenelson263b0292012-03-14 14:55:50 -0700617 if (mCurrentQuery == TOKEN_QUERY_ALL) {
618 if (mLoadingMsgView.getAlpha() == 1) {
619 // Loading message is showing, let it stay a bit more (to prevent
620 // flashing) by adding a start delay to the event animation
621 long timeDiff = LOADING_MSG_MIN_DISPLAY_TIME - (System.currentTimeMillis() -
622 mLoadingMsgStartTime);
623 if (timeDiff > 0) {
624 mAnimateAlpha.setStartDelay(timeDiff);
625 }
626 }
Isaac Katzenelson80d640f2012-04-20 09:21:28 -0700627 if (!mAnimateAlpha.isRunning() &&!mAnimateAlpha.isStarted() && !mNoCrossFade) {
628 mAnimateAlpha.start();
629 } else {
630 mScrollView.setAlpha(1);
631 mLoadingMsgView.setVisibility(View.GONE);
632 }
Isaac Katzenelson263b0292012-03-14 14:55:50 -0700633 }
Mason Tang2bebde72010-08-04 17:20:24 -0700634 }
Mason Tang2bebde72010-08-04 17:20:24 -0700635 }
636
Erik259b8f92011-01-12 14:01:12 -0800637 private void sendAccessibilityEventIfQueryDone(int token) {
638 mCurrentQuery |= token;
639 if (mCurrentQuery == TOKEN_QUERY_ALL) {
640 sendAccessibilityEvent();
641 }
642 }
643
Michael Chan0a01fd32011-01-23 15:13:28 -0800644 public EventInfoFragment(Context context, Uri uri, long startMillis, long endMillis,
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -0800645 int attendeeResponse, boolean isDialog, int windowStyle,
646 ArrayList<ReminderEntry> reminders) {
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700647
Michael Chan2c8485c2012-05-09 10:23:45 -0700648 Resources r = context.getResources();
649 if (mScale == 0) {
650 mScale = context.getResources().getDisplayMetrics().density;
651 if (mScale != 1) {
652 mCustomAppIconSize *= mScale;
653 if (isDialog) {
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700654 DIALOG_TOP_MARGIN *= mScale;
655 }
Michael Chan0a01fd32011-01-23 15:13:28 -0800656 }
657 }
Michael Chan363aa9c2012-05-17 10:31:32 -0700658 if (isDialog) {
659 setDialogSize(r);
660 }
Isaac Katzenelson60f01c22011-06-03 15:42:01 -0700661 mIsDialog = isDialog;
Isaac Katzenelsonc0624ee2011-06-03 09:24:27 -0700662
Michael Chan2fc6b792011-01-26 17:12:44 -0800663 setStyle(DialogFragment.STYLE_NO_TITLE, 0);
Mason Tang2bebde72010-08-04 17:20:24 -0700664 mUri = uri;
665 mStartMillis = startMillis;
666 mEndMillis = endMillis;
667 mAttendeeResponseFromIntent = attendeeResponse;
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700668 mWindowStyle = windowStyle;
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -0800669
670 // Pass in null if no reminders are being specified.
671 // This may be used to explicitly show certain reminders already known
672 // about, such as during configuration changes.
673 mReminders = reminders;
Mason Tang2bebde72010-08-04 17:20:24 -0700674 }
675
Andy McFaddenef31a982011-06-09 07:38:56 -0700676 // This is currently required by the fragment manager.
Isaac Katzenelson60f01c22011-06-03 15:42:01 -0700677 public EventInfoFragment() {
678 }
679
Michael Chan0a01fd32011-01-23 15:13:28 -0800680 public EventInfoFragment(Context context, long eventId, long startMillis, long endMillis,
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -0800681 int attendeeResponse, boolean isDialog, int windowStyle,
682 ArrayList<ReminderEntry> reminders) {
Michael Chan0a01fd32011-01-23 15:13:28 -0800683 this(context, ContentUris.withAppendedId(Events.CONTENT_URI, eventId), startMillis,
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -0800684 endMillis, attendeeResponse, isDialog, windowStyle, reminders);
Mason Tang4003d1c2010-08-17 13:50:45 -0700685 mEventId = eventId;
686 }
687
Michael Chan71d08832010-08-25 18:28:59 -0700688 @Override
689 public void onActivityCreated(Bundle savedInstanceState) {
690 super.onActivityCreated(savedInstanceState);
691
RoboErik8b5743c2011-09-27 16:07:09 -0700692 mReminderChangeListener = new OnItemSelectedListener() {
693 @Override
694 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
695 Integer prevValue = (Integer) parent.getTag();
696 if (prevValue == null || prevValue != position) {
697 parent.setTag(position);
698 mUserModifiedReminders = true;
699 }
700 }
701
702 @Override
703 public void onNothingSelected(AdapterView<?> parent) {
704 // do nothing
705 }
706
707 };
708
Michael Chan71d08832010-08-25 18:28:59 -0700709 if (savedInstanceState != null) {
710 mIsDialog = savedInstanceState.getBoolean(BUNDLE_KEY_IS_DIALOG, false);
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700711 mWindowStyle = savedInstanceState.getInt(BUNDLE_KEY_WINDOW_STYLE,
712 DIALOG_WINDOW_STYLE);
Michael Chan71d08832010-08-25 18:28:59 -0700713 }
714
715 if (mIsDialog) {
716 applyDialogParams();
717 }
James Kung2fca0242013-04-02 16:09:50 -0700718
719 final Activity activity = getActivity();
720 mContext = activity;
721 mColorPickerDialog = (EventColorPickerDialog) activity.getFragmentManager()
722 .findFragmentByTag(COLOR_PICKER_DIALOG_TAG);
723 if (mColorPickerDialog != null) {
724 mColorPickerDialog.setOnColorSelectedListener(this);
725 }
Michael Chan71d08832010-08-25 18:28:59 -0700726 }
727
728 private void applyDialogParams() {
729 Dialog dialog = getDialog();
730 dialog.setCanceledOnTouchOutside(true);
731
732 Window window = dialog.getWindow();
733 window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
734
735 WindowManager.LayoutParams a = window.getAttributes();
736 a.dimAmount = .4f;
737
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700738 a.width = mDialogWidth;
739 a.height = mDialogHeight;
Michael Chan71d08832010-08-25 18:28:59 -0700740
Michael Chan71d08832010-08-25 18:28:59 -0700741
Isaac Katzenelson0b1bd102011-04-07 14:26:29 -0700742 // On tablets , do smart positioning of dialog
743 // On phones , use the whole screen
744
Isaac Katzenelson60f01c22011-06-03 15:42:01 -0700745 if (mX != -1 || mY != -1) {
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700746 a.x = mX - mDialogWidth / 2;
747 a.y = mY - mDialogHeight / 2;
Isaac Katzenelson0aa0c612011-10-03 16:46:10 -0700748 if (a.y < mMinTop) {
749 a.y = mMinTop + DIALOG_TOP_MARGIN;
Isaac Katzenelson0b1bd102011-04-07 14:26:29 -0700750 }
Isaac Katzenelson60f01c22011-06-03 15:42:01 -0700751 a.gravity = Gravity.LEFT | Gravity.TOP;
Isaac Katzenelson0b1bd102011-04-07 14:26:29 -0700752 }
Michael Chan71d08832010-08-25 18:28:59 -0700753 window.setAttributes(a);
754 }
755
Isaac Katzenelson0aa0c612011-10-03 16:46:10 -0700756 public void setDialogParams(int x, int y, int minTop) {
Michael Chan71d08832010-08-25 18:28:59 -0700757 mX = x;
758 mY = y;
Isaac Katzenelson0aa0c612011-10-03 16:46:10 -0700759 mMinTop = minTop;
Michael Chan71d08832010-08-25 18:28:59 -0700760 }
761
Michael Chanf92f46b2010-10-27 18:59:05 -0700762 // Implements OnCheckedChangeListener
763 @Override
764 public void onCheckedChanged(RadioGroup group, int checkedId) {
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800765 // If we haven't finished the return from the dialog yet, don't display.
766 if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
767 return;
768 }
769
Mason Tang2bebde72010-08-04 17:20:24 -0700770 // If this is not a repeating event, then don't display the dialog
771 // asking which events to change.
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800772 int response = getResponseFromButtonId(checkedId);
Mason Tang2bebde72010-08-04 17:20:24 -0700773 if (!mIsRepeating) {
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800774 mUserSetResponse = response;
Mason Tang2bebde72010-08-04 17:20:24 -0700775 return;
776 }
777
778 // If the selection is the same as the original, then don't display the
779 // dialog asking which events to change.
Michael Chanf92f46b2010-10-27 18:59:05 -0700780 if (checkedId == findButtonIdForResponse(mOriginalAttendeeResponse)) {
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800781 mUserSetResponse = response;
Mason Tang2bebde72010-08-04 17:20:24 -0700782 return;
783 }
784
785 // This is a repeating event. We need to ask the user if they mean to
786 // change just this one instance or all instances.
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800787 mTentativeUserSetResponse = response;
788 mEditResponseHelper.showDialog(mWhichEvents);
Mason Tang2bebde72010-08-04 17:20:24 -0700789 }
790
791 public void onNothingSelected(AdapterView<?> parent) {
792 }
793
794 @Override
James Kung4afba182012-12-18 23:12:08 -0800795 public void onDetach() {
796 super.onDetach();
797 mController.deregisterEventHandler(R.layout.event_info);
798 }
799
800 @Override
Mason Tang2bebde72010-08-04 17:20:24 -0700801 public void onAttach(Activity activity) {
802 super.onAttach(activity);
Isaac Katzenelson10b60212011-06-28 17:59:14 -0700803 mActivity = activity;
James Kung1dadfa22013-04-11 19:22:41 -0700804 // Ensure that mIsTabletConfig is set before creating the menu.
James Kung00544122013-04-15 12:15:22 -0700805 mIsTabletConfig = Utils.getConfigBool(mActivity, R.bool.tablet_config);
James Kung4afba182012-12-18 23:12:08 -0800806 mController = CalendarController.getInstance(mActivity);
807 mController.registerEventHandler(R.layout.event_info, this);
Mason Tang2bebde72010-08-04 17:20:24 -0700808 mEditResponseHelper = new EditResponseHelper(activity);
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800809 mEditResponseHelper.setDismissListener(
810 new DialogInterface.OnDismissListener() {
811 @Override
812 public void onDismiss(DialogInterface dialog) {
813 // If the user dismisses the dialog (without hitting OK),
814 // then we want to revert the selection that opened the dialog.
815 if (mEditResponseHelper.getWhichEvents() != -1) {
816 mUserSetResponse = mTentativeUserSetResponse;
817 mWhichEvents = mEditResponseHelper.getWhichEvents();
818 } else {
819 // Revert the attending response radio selection to whatever
820 // was selected prior to this selection (possibly nothing).
821 int oldResponse;
822 if (mUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
823 oldResponse = mUserSetResponse;
824 } else {
825 oldResponse = mOriginalAttendeeResponse;
826 }
827 int buttonToCheck = findButtonIdForResponse(oldResponse);
828
829 if (mResponseRadioGroup != null) {
830 mResponseRadioGroup.check(buttonToCheck);
831 }
832
833 // If the radio group is being cleared, also clear the
834 // dialog's selection of which events should be included
835 // in this response.
836 if (buttonToCheck == -1) {
837 mEditResponseHelper.setWhichEvents(-1);
838 }
839 }
840
841 // Since OnPause will force the dialog to dismiss, do
842 // not change the dialog status
843 if (!mIsPaused) {
844 mTentativeUserSetResponse = Attendees.ATTENDEE_STATUS_NONE;
845 }
846 }
847 });
RoboErik86550ce2011-08-22 16:47:51 -0700848
849 if (mAttendeeResponseFromIntent != Attendees.ATTENDEE_STATUS_NONE) {
850 mEditResponseHelper.setWhichEvents(UPDATE_ALL);
James Kung96267162013-05-01 11:42:57 -0700851 mWhichEvents = mEditResponseHelper.getWhichEvents();
RoboErik86550ce2011-08-22 16:47:51 -0700852 }
Mason Tang2bebde72010-08-04 17:20:24 -0700853 mHandler = new QueryHandler(activity);
Isaac Katzenelson60f01c22011-06-03 15:42:01 -0700854 if (!mIsDialog) {
855 setHasOptionsMenu(true);
856 }
Mason Tang2bebde72010-08-04 17:20:24 -0700857 }
858
859 @Override
860 public View onCreateView(LayoutInflater inflater, ViewGroup container,
861 Bundle savedInstanceState) {
Isaac Katzenelson320c1b12011-11-07 15:31:45 -0800862
863 if (savedInstanceState != null) {
864 mIsDialog = savedInstanceState.getBoolean(BUNDLE_KEY_IS_DIALOG, false);
865 mWindowStyle = savedInstanceState.getInt(BUNDLE_KEY_WINDOW_STYLE,
866 DIALOG_WINDOW_STYLE);
867 mDeleteDialogVisible =
868 savedInstanceState.getBoolean(BUNDLE_KEY_DELETE_DIALOG_VISIBLE,false);
James Kung4afba182012-12-18 23:12:08 -0800869 mCalendarColor = savedInstanceState.getInt(BUNDLE_KEY_CALENDAR_COLOR);
James Kungf56b1492013-03-07 15:10:13 -0800870 mCalendarColorInitialized =
871 savedInstanceState.getBoolean(BUNDLE_KEY_CALENDAR_COLOR_INIT);
James Kung4afba182012-12-18 23:12:08 -0800872 mOriginalColor = savedInstanceState.getInt(BUNDLE_KEY_ORIGINAL_COLOR);
James Kungf56b1492013-03-07 15:10:13 -0800873 mOriginalColorInitialized = savedInstanceState.getBoolean(
874 BUNDLE_KEY_ORIGINAL_COLOR_INIT);
James Kung4afba182012-12-18 23:12:08 -0800875 mCurrentColor = savedInstanceState.getInt(BUNDLE_KEY_CURRENT_COLOR);
James Kungf56b1492013-03-07 15:10:13 -0800876 mCurrentColorInitialized = savedInstanceState.getBoolean(
877 BUNDLE_KEY_CURRENT_COLOR_INIT);
James Kung497a6252013-05-17 14:47:33 -0700878 mCurrentColorKey = savedInstanceState.getInt(BUNDLE_KEY_CURRENT_COLOR_KEY);
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -0800879
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800880 mTentativeUserSetResponse = savedInstanceState.getInt(
881 BUNDLE_KEY_TENTATIVE_USER_RESPONSE,
882 Attendees.ATTENDEE_STATUS_NONE);
883 if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE &&
884 mEditResponseHelper != null) {
885 // If the edit response helper dialog is open, we'll need to
886 // know if either of the choices were selected.
887 mEditResponseHelper.setWhichEvents(savedInstanceState.getInt(
888 BUNDLE_KEY_RESPONSE_WHICH_EVENTS, -1));
889 }
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -0800890 mUserSetResponse = savedInstanceState.getInt(
891 BUNDLE_KEY_USER_SET_ATTENDEE_RESPONSE,
892 Attendees.ATTENDEE_STATUS_NONE);
893 if (mUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
894 // If the response was set by the user before a configuration
895 // change, we'll need to know which choice was selected.
896 mWhichEvents = savedInstanceState.getInt(
897 BUNDLE_KEY_RESPONSE_WHICH_EVENTS, -1);
898 }
899
900 mReminders = Utils.readRemindersFromBundle(savedInstanceState);
Isaac Katzenelson320c1b12011-11-07 15:31:45 -0800901 }
902
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700903 if (mWindowStyle == DIALOG_WINDOW_STYLE) {
Michael Chancba7f1f2011-11-07 17:05:59 -0800904 mView = inflater.inflate(R.layout.event_info_dialog, container, false);
Isaac Katzenelson7ef29812011-10-25 18:00:50 -0700905 } else {
906 mView = inflater.inflate(R.layout.event_info, container, false);
907 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -0700908 mScrollView = (ScrollView) mView.findViewById(R.id.event_info_scroll_view);
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800909 mLoadingMsgView = mView.findViewById(R.id.event_info_loading_msg);
Erik259b8f92011-01-12 14:01:12 -0800910 mTitle = (TextView) mView.findViewById(R.id.title);
Sara Ting75f53662012-04-09 15:37:10 -0700911 mWhenDateTime = (TextView) mView.findViewById(R.id.when_datetime);
Erik259b8f92011-01-12 14:01:12 -0800912 mWhere = (TextView) mView.findViewById(R.id.where);
Michael Chan99704a22011-11-11 10:24:37 -0800913 mDesc = (ExpandableTextView) mView.findViewById(R.id.description);
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -0700914 mHeadlines = mView.findViewById(R.id.event_info_headline);
James Kung4afba182012-12-18 23:12:08 -0800915 mLongAttendees = (AttendeesView) mView.findViewById(R.id.long_attendee_list);
916
Sam Blitzstein3b91cc02013-02-11 17:01:11 -0800917 mResponseRadioGroup = (RadioGroup) mView.findViewById(R.id.response_value);
Mason Tang2bebde72010-08-04 17:20:24 -0700918
Mason Tang4003d1c2010-08-17 13:50:45 -0700919 if (mUri == null) {
920 // restore event ID from bundle
921 mEventId = savedInstanceState.getLong(BUNDLE_KEY_EVENT_ID);
922 mUri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId);
923 mStartMillis = savedInstanceState.getLong(BUNDLE_KEY_START_MILLIS);
924 mEndMillis = savedInstanceState.getLong(BUNDLE_KEY_END_MILLIS);
925 }
926
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800927 mAnimateAlpha = ObjectAnimator.ofFloat(mScrollView, "Alpha", 0, 1);
928 mAnimateAlpha.setDuration(FADE_IN_TIME);
929 mAnimateAlpha.addListener(new AnimatorListenerAdapter() {
930 int defLayerType;
931
932 @Override
933 public void onAnimationStart(Animator animation) {
934 // Use hardware layer for better performance during animation
935 defLayerType = mScrollView.getLayerType();
936 mScrollView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
937 // Ensure that the loading message is gone before showing the
938 // event info
Isaac Katzenelson263b0292012-03-14 14:55:50 -0700939 mLoadingMsgView.removeCallbacks(mLoadingMsgAlphaUpdater);
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800940 mLoadingMsgView.setVisibility(View.GONE);
941 }
942
943 @Override
944 public void onAnimationCancel(Animator animation) {
945 mScrollView.setLayerType(defLayerType, null);
946 }
947
948 @Override
949 public void onAnimationEnd(Animator animation) {
950 mScrollView.setLayerType(defLayerType, null);
Isaac Katzenelson80d640f2012-04-20 09:21:28 -0700951 // Do not cross fade after the first time
952 mNoCrossFade = true;
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800953 }
954 });
955
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -0800956 mLoadingMsgView.setAlpha(0);
957 mScrollView.setAlpha(0);
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.
1055 * @return true if the cursor is empty.
1056 */
1057 private boolean initEventCursor() {
1058 if ((mEventCursor == null) || (mEventCursor.getCount() == 0)) {
1059 return true;
1060 }
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);
Mason Tang2bebde72010-08-04 17:20:24 -07001071 return false;
1072 }
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
Mason Tang2bebde72010-08-04 17:20:24 -07001461 private void updateEvent(View view) {
Isaac Katzenelsonb7762cf2011-06-09 14:04:42 -07001462 if (mEventCursor == null || view == null) {
Mason Tang2bebde72010-08-04 17:20:24 -07001463 return;
1464 }
1465
Michael Chan5f5ef752012-05-24 17:00:21 -07001466 Context context = view.getContext();
1467 if (context == null) {
1468 return;
1469 }
1470
Mason Tang2bebde72010-08-04 17:20:24 -07001471 String eventName = mEventCursor.getString(EVENT_INDEX_TITLE);
1472 if (eventName == null || eventName.length() == 0) {
1473 eventName = getActivity().getString(R.string.no_title_label);
1474 }
1475
Sara Tingda3ee392012-12-10 15:18:26 -08001476 // 3rd parties might not have specified the start/end time when firing the
1477 // Events.CONTENT_URI intent. Update these with values read from the db.
1478 if (mStartMillis == 0 && mEndMillis == 0) {
1479 mStartMillis = mEventCursor.getLong(EVENT_INDEX_DTSTART);
1480 mEndMillis = mEventCursor.getLong(EVENT_INDEX_DTEND);
1481 if (mEndMillis == 0) {
1482 String duration = mEventCursor.getString(EVENT_INDEX_DURATION);
1483 if (!TextUtils.isEmpty(duration)) {
1484 try {
1485 Duration d = new Duration();
1486 d.parse(duration);
1487 long endMillis = mStartMillis + d.getMillis();
1488 if (endMillis >= mStartMillis) {
1489 mEndMillis = endMillis;
1490 } else {
1491 Log.d(TAG, "Invalid duration string: " + duration);
1492 }
1493 } catch (DateException e) {
1494 Log.d(TAG, "Error parsing duration string " + duration, e);
1495 }
1496 }
1497 if (mEndMillis == 0) {
1498 mEndMillis = mStartMillis;
1499 }
1500 }
1501 }
1502
Michael Chan8b1119b2012-01-06 16:04:55 -08001503 mAllDay = mEventCursor.getInt(EVENT_INDEX_ALL_DAY) != 0;
Mason Tang2bebde72010-08-04 17:20:24 -07001504 String location = mEventCursor.getString(EVENT_INDEX_EVENT_LOCATION);
1505 String description = mEventCursor.getString(EVENT_INDEX_DESCRIPTION);
1506 String rRule = mEventCursor.getString(EVENT_INDEX_RRULE);
Isaac Katzenelsonf6f79772011-06-02 16:29:18 -07001507 String eventTimezone = mEventCursor.getString(EVENT_INDEX_EVENT_TIMEZONE);
Mason Tang2bebde72010-08-04 17:20:24 -07001508
James Kung497a6252013-05-17 14:47:33 -07001509 mHeadlines.setBackgroundColor(mCurrentColor);
Mason Tang2bebde72010-08-04 17:20:24 -07001510
Sara Ting4e926272012-04-19 10:41:56 -07001511 // What
1512 if (eventName != null) {
1513 setTextCommon(view, R.id.title, eventName);
1514 }
1515
Mason Tang2bebde72010-08-04 17:20:24 -07001516 // When
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001517 // Set the date and repeats (if any)
Sara Ting75f53662012-04-09 15:37:10 -07001518 String localTimezone = Utils.getTimeZone(mActivity, mTZUpdater);
Michael Chan5f5ef752012-05-24 17:00:21 -07001519
Sara Ting23acd262012-04-20 13:27:39 -07001520 Resources resources = context.getResources();
1521 String displayedDatetime = Utils.getDisplayedDatetime(mStartMillis, mEndMillis,
1522 System.currentTimeMillis(), localTimezone, mAllDay, context);
Michael Chane8e55722012-05-30 13:59:34 -07001523
1524 String displayedTimezone = null;
1525 if (!mAllDay) {
1526 displayedTimezone = Utils.getDisplayedTimezone(mStartMillis, localTimezone,
1527 eventTimezone);
Sara Ting23acd262012-04-20 13:27:39 -07001528 }
1529 // Display the datetime. Make the timezone (if any) transparent.
1530 if (displayedTimezone == null) {
1531 setTextCommon(view, R.id.when_datetime, displayedDatetime);
1532 } else {
Michael Chane8e55722012-05-30 13:59:34 -07001533 int timezoneIndex = displayedDatetime.length();
1534 displayedDatetime += " " + displayedTimezone;
Sara Ting23acd262012-04-20 13:27:39 -07001535 SpannableStringBuilder sb = new SpannableStringBuilder(displayedDatetime);
1536 ForegroundColorSpan transparentColorSpan = new ForegroundColorSpan(
1537 resources.getColor(R.color.event_info_headline_transparent_color));
1538 sb.setSpan(transparentColorSpan, timezoneIndex, displayedDatetime.length(),
1539 Spannable.SPAN_INCLUSIVE_INCLUSIVE);
1540 setTextCommon(view, R.id.when_datetime, sb);
1541 }
Isaac Katzenelson74c90322011-06-02 15:20:29 -07001542
Sara Ting75f53662012-04-09 15:37:10 -07001543 // Display the repeat string (if any)
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001544 String repeatString = null;
Michael Chanbfa0e3f2010-12-20 12:36:55 -08001545 if (!TextUtils.isEmpty(rRule)) {
Mason Tang2bebde72010-08-04 17:20:24 -07001546 EventRecurrence eventRecurrence = new EventRecurrence();
1547 eventRecurrence.parse(rRule);
Sara Ting75f53662012-04-09 15:37:10 -07001548 Time date = new Time(localTimezone);
1549 date.set(mStartMillis);
Michael Chan8b1119b2012-01-06 16:04:55 -08001550 if (mAllDay) {
Mason Tang2bebde72010-08-04 17:20:24 -07001551 date.timezone = Time.TIMEZONE_UTC;
1552 }
Mason Tang2bebde72010-08-04 17:20:24 -07001553 eventRecurrence.setStartDate(date);
Michael Chanb21c6382013-03-14 02:53:30 -07001554 repeatString = EventRecurrenceFormatter.getRepeatString(mContext, resources,
1555 eventRecurrence, true);
Mason Tang2bebde72010-08-04 17:20:24 -07001556 }
Sara Ting75f53662012-04-09 15:37:10 -07001557 if (repeatString == null) {
1558 view.findViewById(R.id.when_repeat).setVisibility(View.GONE);
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001559 } else {
Sara Ting75f53662012-04-09 15:37:10 -07001560 setTextCommon(view, R.id.when_repeat, repeatString);
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001561 }
1562
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001563 // Organizer view is setup in the updateCalendar method
1564
Mason Tang2bebde72010-08-04 17:20:24 -07001565
1566 // Where
Michael Chanddfb59d2011-01-12 15:41:21 -08001567 if (location == null || location.trim().length() == 0) {
Mason Tang2bebde72010-08-04 17:20:24 -07001568 setVisibilityCommon(view, R.id.where, View.GONE);
1569 } else {
Erik259b8f92011-01-12 14:01:12 -08001570 final TextView textView = mWhere;
Mason Tang2bebde72010-08-04 17:20:24 -07001571 if (textView != null) {
Michael Chanddfb59d2011-01-12 15:41:21 -08001572 textView.setAutoLinkMask(0);
1573 textView.setText(location.trim());
Andy McFaddenaf577fd2011-11-07 11:08:14 -08001574 try {
Sam Blitzstein29dc76a2012-11-19 10:46:54 -08001575 textView.setText(Utils.extendedLinkify(textView.getText().toString(), true));
1576
1577 // Linkify.addLinks() sets the TextView movement method if it finds any links.
Sara Tingda3ee392012-12-10 15:18:26 -08001578 // We must do the same here, in case linkify by itself did not find any.
Sam Blitzstein29dc76a2012-11-19 10:46:54 -08001579 // (This is cloned from Linkify.addLinkMovementMethod().)
1580 MovementMethod mm = textView.getMovementMethod();
1581 if ((mm == null) || !(mm instanceof LinkMovementMethod)) {
1582 if (textView.getLinksClickable()) {
1583 textView.setMovementMethod(LinkMovementMethod.getInstance());
1584 }
1585 }
Andy McFaddenaf577fd2011-11-07 11:08:14 -08001586 } catch (Exception ex) {
1587 // unexpected
1588 Log.e(TAG, "Linkification failed", ex);
1589 }
Andy McFadden73b07652011-08-23 15:45:09 -07001590
Michael Chanddfb59d2011-01-12 15:41:21 -08001591 textView.setOnTouchListener(new OnTouchListener() {
Andy McFaddenc928e3d2011-06-13 09:53:20 -07001592 @Override
Michael Chanddfb59d2011-01-12 15:41:21 -08001593 public boolean onTouch(View v, MotionEvent event) {
1594 try {
1595 return v.onTouchEvent(event);
1596 } catch (ActivityNotFoundException e) {
1597 // ignore
1598 return true;
Mason Tang2bebde72010-08-04 17:20:24 -07001599 }
Michael Chanddfb59d2011-01-12 15:41:21 -08001600 }
1601 });
Mason Tang2bebde72010-08-04 17:20:24 -07001602 }
1603 }
1604
1605 // Description
Michael Chan352e1a22010-09-28 05:15:08 -07001606 if (description != null && description.length() != 0) {
Michael Chan99704a22011-11-11 10:24:37 -08001607 mDesc.setText(description);
Mason Tang2bebde72010-08-04 17:20:24 -07001608 }
Mason Tang2bebde72010-08-04 17:20:24 -07001609
Michael Chan2c8485c2012-05-09 10:23:45 -07001610 // Launch Custom App
Sara Tingfac2d152012-05-31 14:59:57 -07001611 if (Utils.isJellybeanOrLater()) {
Michael Chan693ca602012-05-31 12:24:11 -07001612 updateCustomAppButton();
1613 }
Michael Chan2c8485c2012-05-09 10:23:45 -07001614 }
1615
1616 private void updateCustomAppButton() {
1617 buttonSetup: {
1618 final Button launchButton = (Button) mView.findViewById(R.id.launch_custom_app_button);
1619 if (launchButton == null)
1620 break buttonSetup;
1621
1622 final String customAppPackage = mEventCursor.getString(EVENT_INDEX_CUSTOM_APP_PACKAGE);
1623 final String customAppUri = mEventCursor.getString(EVENT_INDEX_CUSTOM_APP_URI);
1624
1625 if (TextUtils.isEmpty(customAppPackage) || TextUtils.isEmpty(customAppUri))
1626 break buttonSetup;
1627
1628 PackageManager pm = mContext.getPackageManager();
1629 if (pm == null)
1630 break buttonSetup;
1631
1632 ApplicationInfo info;
1633 try {
1634 info = pm.getApplicationInfo(customAppPackage, 0);
1635 if (info == null)
1636 break buttonSetup;
1637 } catch (NameNotFoundException e) {
1638 break buttonSetup;
1639 }
1640
1641 Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId);
1642 final Intent intent = new Intent(CalendarContract.ACTION_HANDLE_CUSTOM_EVENT, uri);
1643 intent.setPackage(customAppPackage);
1644 intent.putExtra(CalendarContract.EXTRA_CUSTOM_APP_URI, customAppUri);
1645 intent.putExtra(EXTRA_EVENT_BEGIN_TIME, mStartMillis);
1646
1647 // See if we have a taker for our intent
1648 if (pm.resolveActivity(intent, 0) == null)
1649 break buttonSetup;
1650
1651 Drawable icon = pm.getApplicationIcon(info);
1652 if (icon != null) {
1653
1654 Drawable[] d = launchButton.getCompoundDrawables();
1655 icon.setBounds(0, 0, mCustomAppIconSize, mCustomAppIconSize);
1656 launchButton.setCompoundDrawables(icon, d[1], d[2], d[3]);
1657 }
1658
1659 CharSequence label = pm.getApplicationLabel(info);
1660 if (label != null && label.length() != 0) {
1661 launchButton.setText(label);
1662 } else if (icon == null) {
1663 // No icon && no label. Hide button?
1664 break buttonSetup;
1665 }
1666
1667 // Launch custom app
1668 launchButton.setOnClickListener(new View.OnClickListener() {
1669 @Override
1670 public void onClick(View v) {
1671 try {
1672 startActivityForResult(intent, 0);
1673 } catch (ActivityNotFoundException e) {
1674 // Shouldn't happen as we checked it already
1675 setVisibilityCommon(mView, R.id.launch_custom_app_container, View.GONE);
1676 }
1677 }
1678 });
1679
1680 setVisibilityCommon(mView, R.id.launch_custom_app_container, View.VISIBLE);
1681 return;
1682
1683 }
1684
1685 setVisibilityCommon(mView, R.id.launch_custom_app_container, View.GONE);
1686 return;
Isaac Katzenelson8f4d9692012-02-23 17:34:07 -08001687 }
Sara Ting75f53662012-04-09 15:37:10 -07001688
Erik259b8f92011-01-12 14:01:12 -08001689 private void sendAccessibilityEvent() {
Andy McFaddenef31a982011-06-09 07:38:56 -07001690 AccessibilityManager am =
1691 (AccessibilityManager) getActivity().getSystemService(Service.ACCESSIBILITY_SERVICE);
Erik259b8f92011-01-12 14:01:12 -08001692 if (!am.isEnabled()) {
1693 return;
1694 }
1695
1696 AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_FOCUSED);
1697 event.setClassName(getClass().getName());
1698 event.setPackageName(getActivity().getPackageName());
1699 List<CharSequence> text = event.getText();
1700
Michael Chan99704a22011-11-11 10:24:37 -08001701 addFieldToAccessibilityEvent(text, mTitle, null);
Sara Ting75f53662012-04-09 15:37:10 -07001702 addFieldToAccessibilityEvent(text, mWhenDateTime, null);
Michael Chan99704a22011-11-11 10:24:37 -08001703 addFieldToAccessibilityEvent(text, mWhere, null);
1704 addFieldToAccessibilityEvent(text, null, mDesc);
Erik259b8f92011-01-12 14:01:12 -08001705
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08001706 if (mResponseRadioGroup.getVisibility() == View.VISIBLE) {
1707 int id = mResponseRadioGroup.getCheckedRadioButtonId();
Erik259b8f92011-01-12 14:01:12 -08001708 if (id != View.NO_ID) {
1709 text.add(((TextView) getView().findViewById(R.id.response_label)).getText());
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08001710 text.add((((RadioButton) (mResponseRadioGroup.findViewById(id)))
1711 .getText() + PERIOD_SPACE));
Erik259b8f92011-01-12 14:01:12 -08001712 }
1713 }
1714
1715 am.sendAccessibilityEvent(event);
1716 }
1717
Michael Chan99704a22011-11-11 10:24:37 -08001718 private void addFieldToAccessibilityEvent(List<CharSequence> text, TextView tv,
1719 ExpandableTextView etv) {
Michael Chan33893972011-11-16 12:45:53 -08001720 CharSequence cs;
Michael Chan99704a22011-11-11 10:24:37 -08001721 if (tv != null) {
Michael Chan33893972011-11-16 12:45:53 -08001722 cs = tv.getText();
Michael Chan99704a22011-11-11 10:24:37 -08001723 } else if (etv != null) {
Michael Chan33893972011-11-16 12:45:53 -08001724 cs = etv.getText();
Michael Chan99704a22011-11-11 10:24:37 -08001725 } else {
Isaac Katzenelson9ceed1f2011-06-08 17:26:26 -07001726 return;
1727 }
Michael Chan99704a22011-11-11 10:24:37 -08001728
Michael Chan33893972011-11-16 12:45:53 -08001729 if (!TextUtils.isEmpty(cs)) {
1730 cs = cs.toString().trim();
1731 if (cs.length() > 0) {
1732 text.add(cs);
1733 text.add(PERIOD_SPACE);
1734 }
Erik259b8f92011-01-12 14:01:12 -08001735 }
1736 }
1737
Mason Tang2bebde72010-08-04 17:20:24 -07001738 private void updateCalendar(View view) {
James Kung4afba182012-12-18 23:12:08 -08001739
Mason Tang2bebde72010-08-04 17:20:24 -07001740 mCalendarOwnerAccount = "";
1741 if (mCalendarsCursor != null && mEventCursor != null) {
1742 mCalendarsCursor.moveToFirst();
1743 String tempAccount = mCalendarsCursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
1744 mCalendarOwnerAccount = (tempAccount == null) ? "" : tempAccount;
Michael Chan352e1a22010-09-28 05:15:08 -07001745 mOwnerCanRespond = mCalendarsCursor.getInt(CALENDARS_INDEX_OWNER_CAN_RESPOND) != 0;
Sara Ting42896f72012-03-15 15:24:36 -07001746 mSyncAccountName = mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_NAME);
Mason Tang2bebde72010-08-04 17:20:24 -07001747
Sara Ting6aad0ff2012-08-02 10:55:52 -07001748 // start visible calendars query
1749 mHandler.startQuery(TOKEN_QUERY_VISIBLE_CALENDARS, null, Calendars.CONTENT_URI,
1750 CALENDARS_PROJECTION, CALENDARS_VISIBLE_WHERE, new String[] {"1"}, null);
Mason Tang2bebde72010-08-04 17:20:24 -07001751
Michael Chan83efa2d2012-04-24 17:42:21 -07001752 mEventOrganizerEmail = mEventCursor.getString(EVENT_INDEX_ORGANIZER);
1753 mIsOrganizer = mCalendarOwnerAccount.equalsIgnoreCase(mEventOrganizerEmail);
1754
Sara Ting0c0da942012-04-27 10:35:05 -07001755 if (!TextUtils.isEmpty(mEventOrganizerEmail) &&
1756 !mEventOrganizerEmail.endsWith(Utils.MACHINE_GENERATED_ADDRESS)) {
Michael Chan83efa2d2012-04-24 17:42:21 -07001757 mEventOrganizerDisplayName = mEventOrganizerEmail;
1758 }
1759
1760 if (!mIsOrganizer && !TextUtils.isEmpty(mEventOrganizerDisplayName)) {
1761 setTextCommon(view, R.id.organizer, mEventOrganizerDisplayName);
Isaac Katzenelsonb7762cf2011-06-09 14:04:42 -07001762 setVisibilityCommon(view, R.id.organizer_container, View.VISIBLE);
1763 } else {
1764 setVisibilityCommon(view, R.id.organizer_container, View.GONE);
1765 }
Mason Tang2bebde72010-08-04 17:20:24 -07001766 mHasAttendeeData = mEventCursor.getInt(EVENT_INDEX_HAS_ATTENDEE_DATA) != 0;
RoboErik65eeb792011-08-08 12:54:00 -07001767 mCanModifyCalendar = mEventCursor.getInt(EVENT_INDEX_ACCESS_LEVEL)
1768 >= Calendars.CAL_ACCESS_CONTRIBUTOR;
1769 // TODO add "|| guestCanModify" after b/1299071 is fixed
1770 mCanModifyEvent = mCanModifyCalendar && mIsOrganizer;
Mason Tang2bebde72010-08-04 17:20:24 -07001771 mIsBusyFreeCalendar =
RoboErikef2add92011-06-09 14:49:53 -07001772 mEventCursor.getInt(EVENT_INDEX_ACCESS_LEVEL) == Calendars.CAL_ACCESS_FREEBUSY;
Michael Chan352e1a22010-09-28 05:15:08 -07001773
1774 if (!mIsBusyFreeCalendar) {
Isaac Katzenelsond4e45fa2012-06-04 16:38:11 -07001775
1776 View b = mView.findViewById(R.id.edit);
Michael Chan352e1a22010-09-28 05:15:08 -07001777 b.setEnabled(true);
Michael Chan8ce3b7d2010-09-01 15:41:01 -07001778 b.setOnClickListener(new OnClickListener() {
1779 @Override
1780 public void onClick(View v) {
1781 doEdit();
Isaac Katzenelson10b60212011-06-28 17:59:14 -07001782 // For dialogs, just close the fragment
1783 // For full screen, close activity on phone, leave it for tablet
Isaac Katzenelson60f01c22011-06-03 15:42:01 -07001784 if (mIsDialog) {
1785 EventInfoFragment.this.dismiss();
1786 }
Isaac Katzenelson10b60212011-06-28 17:59:14 -07001787 else if (!mIsTabletConfig){
Isaac Katzenelson60f01c22011-06-03 15:42:01 -07001788 getActivity().finish();
1789 }
Michael Chan352e1a22010-09-28 05:15:08 -07001790 }
1791 });
Michael Chan8ce3b7d2010-09-01 15:41:01 -07001792 }
Mindy Pereiradd151692011-08-29 14:05:26 -07001793 View button;
Sara Ting42896f72012-03-15 15:24:36 -07001794 if (mCanModifyCalendar) {
Mindy Pereiradd151692011-08-29 14:05:26 -07001795 button = mView.findViewById(R.id.delete);
1796 if (button != null) {
Sara Ting42896f72012-03-15 15:24:36 -07001797 button.setEnabled(true);
1798 button.setVisibility(View.VISIBLE);
RoboErik65eeb792011-08-08 12:54:00 -07001799 }
Mindy Pereiradd151692011-08-29 14:05:26 -07001800 }
Sara Ting42896f72012-03-15 15:24:36 -07001801 if (mCanModifyEvent) {
Mindy Pereiradd151692011-08-29 14:05:26 -07001802 button = mView.findViewById(R.id.edit);
1803 if (button != null) {
Sara Ting42896f72012-03-15 15:24:36 -07001804 button.setEnabled(true);
1805 button.setVisibility(View.VISIBLE);
Isaac Katzenelson60f01c22011-06-03 15:42:01 -07001806 }
RoboErikd8353fb2011-07-21 11:28:11 -07001807 }
Isaac Katzenelson7ef29812011-10-25 18:00:50 -07001808 if ((!mIsDialog && !mIsTabletConfig ||
1809 mWindowStyle == EventInfoFragment.FULL_WINDOW_STYLE) && mMenu != null) {
RoboErikd8353fb2011-07-21 11:28:11 -07001810 mActivity.invalidateOptionsMenu();
RoboErik69be8552011-02-14 16:51:59 -08001811 }
Mason Tang2bebde72010-08-04 17:20:24 -07001812 } else {
Michael Chan71b221a2010-10-25 17:55:44 -07001813 setVisibilityCommon(view, R.id.calendar, View.GONE);
Erik259b8f92011-01-12 14:01:12 -08001814 sendAccessibilityEventIfQueryDone(TOKEN_QUERY_DUPLICATE_CALENDARS);
Mason Tang2bebde72010-08-04 17:20:24 -07001815 }
1816 }
1817
RoboErikd8353fb2011-07-21 11:28:11 -07001818 /**
1819 *
1820 */
1821 private void updateMenu() {
1822 if (mMenu == null) {
1823 return;
1824 }
1825 MenuItem delete = mMenu.findItem(R.id.info_action_delete);
1826 MenuItem edit = mMenu.findItem(R.id.info_action_edit);
James Kung4afba182012-12-18 23:12:08 -08001827 MenuItem changeColor = mMenu.findItem(R.id.info_action_change_color);
RoboErikd8353fb2011-07-21 11:28:11 -07001828 if (delete != null) {
1829 delete.setVisible(mCanModifyCalendar);
1830 delete.setEnabled(mCanModifyCalendar);
1831 }
1832 if (edit != null) {
RoboErik65eeb792011-08-08 12:54:00 -07001833 edit.setVisible(mCanModifyEvent);
1834 edit.setEnabled(mCanModifyEvent);
RoboErikd8353fb2011-07-21 11:28:11 -07001835 }
James Kung4afba182012-12-18 23:12:08 -08001836 if (changeColor != null && mColors != null && mColors.length > 0) {
1837 changeColor.setVisible(mCanModifyCalendar);
1838 changeColor.setEnabled(mCanModifyCalendar);
1839 }
RoboErikd8353fb2011-07-21 11:28:11 -07001840 }
1841
Mason Tang2bebde72010-08-04 17:20:24 -07001842 private void updateAttendees(View view) {
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001843 if (mAcceptedAttendees.size() + mDeclinedAttendees.size() +
1844 mTentativeAttendees.size() + mNoResponseAttendees.size() > 0) {
RoboErikc7f3c382011-08-31 14:43:24 -07001845 mLongAttendees.clearAttendees();
RoboErik4acb2fd2011-07-18 15:39:49 -07001846 (mLongAttendees).addAttendees(mAcceptedAttendees);
1847 (mLongAttendees).addAttendees(mDeclinedAttendees);
1848 (mLongAttendees).addAttendees(mTentativeAttendees);
1849 (mLongAttendees).addAttendees(mNoResponseAttendees);
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001850 mLongAttendees.setEnabled(false);
1851 mLongAttendees.setVisibility(View.VISIBLE);
Isaac Katzenelson60f01c22011-06-03 15:42:01 -07001852 } else {
Isaac Katzenelsonfae6d5c2011-06-16 15:43:41 -07001853 mLongAttendees.setVisibility(View.GONE);
Michael Chan71b221a2010-10-25 17:55:44 -07001854 }
Sara Tingcb5f5682012-04-04 22:52:20 -07001855
Sara Ting7ffa24c2012-08-28 15:44:37 -07001856 if (hasEmailableAttendees()) {
Sara Ting7da27672012-07-24 16:23:53 -07001857 setVisibilityCommon(mView, R.id.email_attendees_container, View.VISIBLE);
Sara Ting7ffa24c2012-08-28 15:44:37 -07001858 if (emailAttendeesButton != null) {
1859 emailAttendeesButton.setText(R.string.email_guests_label);
1860 }
1861 } else if (hasEmailableOrganizer()) {
1862 setVisibilityCommon(mView, R.id.email_attendees_container, View.VISIBLE);
1863 if (emailAttendeesButton != null) {
1864 emailAttendeesButton.setText(R.string.email_organizer_label);
1865 }
Sara Ting7da27672012-07-24 16:23:53 -07001866 } else {
1867 setVisibilityCommon(mView, R.id.email_attendees_container, View.GONE);
1868 }
Sara Tingcb5f5682012-04-04 22:52:20 -07001869 }
1870
1871 /**
Sara Ting7da27672012-07-24 16:23:53 -07001872 * Returns true if there is at least 1 attendee that is not the viewer.
Sara Tingcb5f5682012-04-04 22:52:20 -07001873 */
Sara Ting7ffa24c2012-08-28 15:44:37 -07001874 private boolean hasEmailableAttendees() {
Sara Tingcb5f5682012-04-04 22:52:20 -07001875 for (Attendee attendee : mAcceptedAttendees) {
Sara Ting7da27672012-07-24 16:23:53 -07001876 if (Utils.isEmailableFrom(attendee.mEmail, mSyncAccountName)) {
1877 return true;
1878 }
Sara Tingcb5f5682012-04-04 22:52:20 -07001879 }
1880 for (Attendee attendee : mTentativeAttendees) {
Sara Ting7da27672012-07-24 16:23:53 -07001881 if (Utils.isEmailableFrom(attendee.mEmail, mSyncAccountName)) {
1882 return true;
1883 }
Sara Tingcb5f5682012-04-04 22:52:20 -07001884 }
1885 for (Attendee attendee : mNoResponseAttendees) {
Sara Ting7da27672012-07-24 16:23:53 -07001886 if (Utils.isEmailableFrom(attendee.mEmail, mSyncAccountName)) {
1887 return true;
1888 }
Sara Tingcb5f5682012-04-04 22:52:20 -07001889 }
Sara Ting7da27672012-07-24 16:23:53 -07001890 for (Attendee attendee : mDeclinedAttendees) {
1891 if (Utils.isEmailableFrom(attendee.mEmail, mSyncAccountName)) {
1892 return true;
1893 }
Sara Tingcb5f5682012-04-04 22:52:20 -07001894 }
Sara Ting7ffa24c2012-08-28 15:44:37 -07001895 return false;
1896 }
1897
1898 private boolean hasEmailableOrganizer() {
Sara Ting7da27672012-07-24 16:23:53 -07001899 return mEventOrganizerEmail != null &&
1900 Utils.isEmailableFrom(mEventOrganizerEmail, mSyncAccountName);
Michael Chan8ce3b7d2010-09-01 15:41:01 -07001901 }
1902
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001903 public void initReminders(View view, Cursor cursor) {
1904
1905 // Add reminders
RoboErikc7f3c382011-08-31 14:43:24 -07001906 mOriginalReminders.clear();
RoboErikc08957b2011-09-09 13:43:38 -07001907 mUnsupportedReminders.clear();
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001908 while (cursor.moveToNext()) {
1909 int minutes = cursor.getInt(EditEventHelper.REMINDERS_INDEX_MINUTES);
1910 int method = cursor.getInt(EditEventHelper.REMINDERS_INDEX_METHOD);
RoboErike35a0322011-09-01 16:21:49 -07001911
RoboErikc08957b2011-09-09 13:43:38 -07001912 if (method != Reminders.METHOD_DEFAULT && !mReminderMethodValues.contains(method)) {
RoboErike35a0322011-09-01 16:21:49 -07001913 // Stash unsupported reminder types separately so we don't alter
1914 // them in the UI
1915 mUnsupportedReminders.add(ReminderEntry.valueOf(minutes, method));
1916 } else {
1917 mOriginalReminders.add(ReminderEntry.valueOf(minutes, method));
1918 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001919 }
1920 // Sort appropriately for display (by time, then type)
1921 Collections.sort(mOriginalReminders);
1922
RoboErik8b5743c2011-09-27 16:07:09 -07001923 if (mUserModifiedReminders) {
1924 // If the user has changed the list of reminders don't change what's
1925 // shown.
1926 return;
1927 }
1928
RoboErik5d40a382011-09-02 14:33:09 -07001929 LinearLayout parent = (LinearLayout) mScrollView
1930 .findViewById(R.id.reminder_items_container);
1931 if (parent != null) {
1932 parent.removeAllViews();
1933 }
RoboErikc08957b2011-09-09 13:43:38 -07001934 if (mReminderViews != null) {
1935 mReminderViews.clear();
1936 }
RoboErik5d40a382011-09-02 14:33:09 -07001937
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001938 if (mHasAlarm) {
Sam Blitzstein94a1f1a2013-02-12 15:16:35 -08001939 ArrayList<ReminderEntry> reminders;
1940 // If applicable, use reminders saved in the bundle.
1941 if (mReminders != null) {
1942 reminders = mReminders;
1943 } else {
1944 reminders = mOriginalReminders;
1945 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001946 // Insert any minute values that aren't represented in the minutes list.
1947 for (ReminderEntry re : reminders) {
1948 EventViewUtils.addMinutesToList(
1949 mActivity, mReminderMinuteValues, mReminderMinuteLabels, re.getMinutes());
1950 }
1951 // Create a UI element for each reminder. We display all of the reminders we get
1952 // from the provider, even if the count exceeds the calendar maximum. (Also, for
1953 // a new event, we won't have a maxReminders value available.)
1954 for (ReminderEntry re : reminders) {
RoboErike35a0322011-09-01 16:21:49 -07001955 EventViewUtils.addReminder(mActivity, mScrollView, this, mReminderViews,
1956 mReminderMinuteValues, mReminderMinuteLabels, mReminderMethodValues,
RoboErik8b5743c2011-09-27 16:07:09 -07001957 mReminderMethodLabels, re, Integer.MAX_VALUE, mReminderChangeListener);
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001958 }
Sara Ting06f3d6d2012-03-23 17:19:22 -07001959 EventViewUtils.updateAddReminderButton(mView, mReminderViews, mMaxReminders);
RoboErike35a0322011-09-01 16:21:49 -07001960 // TODO show unsupported reminder types in some fashion.
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07001961 }
1962 }
1963
Mason Tang2bebde72010-08-04 17:20:24 -07001964 void updateResponse(View view) {
1965 // we only let the user accept/reject/etc. a meeting if:
1966 // a) you can edit the event's containing calendar AND
1967 // b) you're not the organizer and only attendee AND
1968 // c) organizerCanRespond is enabled for the calendar
1969 // (if the attendee data has been hidden, the visible number of attendees
1970 // will be 1 -- the calendar owner's).
1971 // (there are more cases involved to be 100% accurate, such as
1972 // paying attention to whether or not an attendee status was
1973 // included in the feed, but we're currently omitting those corner cases
1974 // for simplicity).
Michael Chan352e1a22010-09-28 05:15:08 -07001975
1976 // TODO Switch to EditEventHelper.canRespond when this class uses CalendarEventModel.
Michael Chand785cd52010-09-03 13:57:19 -07001977 if (!mCanModifyCalendar || (mHasAttendeeData && mIsOrganizer && mNumOfAttendees <= 1) ||
Michael Chan352e1a22010-09-28 05:15:08 -07001978 (mIsOrganizer && !mOwnerCanRespond)) {
Mason Tang2bebde72010-08-04 17:20:24 -07001979 setVisibilityCommon(view, R.id.response_container, View.GONE);
1980 return;
1981 }
1982
1983 setVisibilityCommon(view, R.id.response_container, View.VISIBLE);
1984
Mason Tang2bebde72010-08-04 17:20:24 -07001985
Michael Chanf92f46b2010-10-27 18:59:05 -07001986 int response;
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08001987 if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
1988 response = mTentativeUserSetResponse;
1989 } else if (mUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
RoboErik5afc0832011-09-27 14:14:09 -07001990 response = mUserSetResponse;
Isaac Katzenelson6bcafcf2012-05-02 18:25:36 -07001991 } else if (mAttendeeResponseFromIntent != Attendees.ATTENDEE_STATUS_NONE) {
Michael Chanf92f46b2010-10-27 18:59:05 -07001992 response = mAttendeeResponseFromIntent;
Mason Tang2bebde72010-08-04 17:20:24 -07001993 } else {
Michael Chanf92f46b2010-10-27 18:59:05 -07001994 response = mOriginalAttendeeResponse;
Mason Tang2bebde72010-08-04 17:20:24 -07001995 }
Michael Chanf92f46b2010-10-27 18:59:05 -07001996
1997 int buttonToCheck = findButtonIdForResponse(response);
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08001998 mResponseRadioGroup.check(buttonToCheck); // -1 clear all radio buttons
1999 mResponseRadioGroup.setOnCheckedChangeListener(this);
Mason Tang2bebde72010-08-04 17:20:24 -07002000 }
2001
2002 private void setTextCommon(View view, int id, CharSequence text) {
2003 TextView textView = (TextView) view.findViewById(id);
2004 if (textView == null)
2005 return;
2006 textView.setText(text);
2007 }
2008
2009 private void setVisibilityCommon(View view, int id, int visibility) {
2010 View v = view.findViewById(id);
2011 if (v != null) {
2012 v.setVisibility(visibility);
2013 }
2014 return;
2015 }
2016
2017 /**
2018 * Taken from com.google.android.gm.HtmlConversationActivity
2019 *
2020 * Send the intent that shows the Contact info corresponding to the email address.
2021 */
2022 public void showContactInfo(Attendee attendee, Rect rect) {
2023 // First perform lookup query to find existing contact
2024 final ContentResolver resolver = getActivity().getContentResolver();
2025 final String address = attendee.mEmail;
2026 final Uri dataUri = Uri.withAppendedPath(CommonDataKinds.Email.CONTENT_FILTER_URI,
2027 Uri.encode(address));
2028 final Uri lookupUri = ContactsContract.Data.getContactLookupUri(resolver, dataUri);
2029
2030 if (lookupUri != null) {
2031 // Found matching contact, trigger QuickContact
2032 QuickContact.showQuickContact(getActivity(), rect, lookupUri,
2033 QuickContact.MODE_MEDIUM, null);
2034 } else {
2035 // No matching contact, ask user to create one
2036 final Uri mailUri = Uri.fromParts("mailto", address, null);
2037 final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, mailUri);
2038
2039 // Pass along full E-mail string for possible create dialog
2040 Rfc822Token sender = new Rfc822Token(attendee.mName, attendee.mEmail, null);
2041 intent.putExtra(Intents.EXTRA_CREATE_DESCRIPTION, sender.toString());
2042
2043 // Only provide personal name hint if we have one
2044 final String senderPersonal = attendee.mName;
2045 if (!TextUtils.isEmpty(senderPersonal)) {
2046 intent.putExtra(Intents.Insert.NAME, senderPersonal);
2047 }
2048
2049 startActivity(intent);
2050 }
2051 }
Erikcb811892010-09-28 13:44:19 -07002052
2053 @Override
RoboErik7c6236d2011-02-24 16:41:18 -08002054 public void onPause() {
2055 mIsPaused = true;
2056 mHandler.removeCallbacks(onDeleteRunnable);
2057 super.onPause();
Isaac Katzenelsonb0a313a2011-10-24 11:41:56 -07002058 // Remove event deletion alert box since it is being rebuild in the OnResume
2059 // This is done to get the same behavior on OnResume since the AlertDialog is gone on
2060 // rotation but not if you press the HOME key
2061 if (mDeleteDialogVisible && mDeleteHelper != null) {
2062 mDeleteHelper.dismissAlertDialog();
2063 mDeleteHelper = null;
2064 }
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08002065 if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE
2066 && mEditResponseHelper != null) {
2067 mEditResponseHelper.dismissAlertDialog();
2068 }
RoboErik7c6236d2011-02-24 16:41:18 -08002069 }
2070
2071 @Override
2072 public void onResume() {
2073 super.onResume();
Michael Chan363aa9c2012-05-17 10:31:32 -07002074 if (mIsDialog) {
2075 setDialogSize(getActivity().getResources());
2076 applyDialogParams();
2077 }
RoboErik7c6236d2011-02-24 16:41:18 -08002078 mIsPaused = false;
2079 if (mDismissOnResume) {
2080 mHandler.post(onDeleteRunnable);
2081 }
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08002082 // Display the "delete confirmation" or "edit response helper" dialog if needed
Isaac Katzenelsonb0a313a2011-10-24 11:41:56 -07002083 if (mDeleteDialogVisible) {
2084 mDeleteHelper = new DeleteEventHelper(
2085 mContext, mActivity,
2086 !mIsDialog && !mIsTabletConfig /* exitWhenDone */);
2087 mDeleteHelper.setOnDismissListener(createDeleteOnDismissListener());
2088 mDeleteHelper.delete(mStartMillis, mEndMillis, mEventId, -1, onDeleteRunnable);
Sam Blitzstein3b91cc02013-02-11 17:01:11 -08002089 } else if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
2090 int buttonId = findButtonIdForResponse(mTentativeUserSetResponse);
2091 mResponseRadioGroup.check(buttonId);
2092 mEditResponseHelper.showDialog(mEditResponseHelper.getWhichEvents());
Isaac Katzenelsonb0a313a2011-10-24 11:41:56 -07002093 }
RoboErik7c6236d2011-02-24 16:41:18 -08002094 }
2095
2096 @Override
Erikcb811892010-09-28 13:44:19 -07002097 public void eventsChanged() {
2098 }
2099
2100 @Override
Erikcb811892010-09-28 13:44:19 -07002101 public long getSupportedEventTypes() {
2102 return EventType.EVENTS_CHANGED;
2103 }
2104
2105 @Override
Erikcb811892010-09-28 13:44:19 -07002106 public void handleEvent(EventInfo event) {
James Kung4afba182012-12-18 23:12:08 -08002107 reloadEvents();
Erikcb811892010-09-28 13:44:19 -07002108 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002109
Isaac Katzenelson80d640f2012-04-20 09:21:28 -07002110 public void reloadEvents() {
James Kung4afba182012-12-18 23:12:08 -08002111 if (mHandler != null) {
2112 mHandler.startQuery(TOKEN_QUERY_EVENT, null, mUri, EVENT_PROJECTION,
2113 null, null, null);
2114 }
Isaac Katzenelson80d640f2012-04-20 09:21:28 -07002115 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002116
2117 @Override
2118 public void onClick(View view) {
2119
2120 // This must be a click on one of the "remove reminder" buttons
2121 LinearLayout reminderItem = (LinearLayout) view.getParent();
2122 LinearLayout parent = (LinearLayout) reminderItem.getParent();
2123 parent.removeView(reminderItem);
2124 mReminderViews.remove(reminderItem);
RoboErik8b5743c2011-09-27 16:07:09 -07002125 mUserModifiedReminders = true;
Sara Ting06f3d6d2012-03-23 17:19:22 -07002126 EventViewUtils.updateAddReminderButton(mView, mReminderViews, mMaxReminders);
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002127 }
2128
2129
2130 /**
2131 * Add a new reminder when the user hits the "add reminder" button. We use the default
2132 * reminder time and method.
2133 */
2134 private void addReminder() {
2135 // TODO: when adding a new reminder, make it different from the
2136 // last one in the list (if any).
2137 if (mDefaultReminderMinutes == GeneralPreferences.NO_REMINDER) {
2138 EventViewUtils.addReminder(mActivity, mScrollView, this, mReminderViews,
RoboErik8b5743c2011-09-27 16:07:09 -07002139 mReminderMinuteValues, mReminderMinuteLabels, mReminderMethodValues,
2140 mReminderMethodLabels,
2141 ReminderEntry.valueOf(GeneralPreferences.REMINDER_DEFAULT_TIME), mMaxReminders,
2142 mReminderChangeListener);
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002143 } else {
2144 EventViewUtils.addReminder(mActivity, mScrollView, this, mReminderViews,
RoboErik8b5743c2011-09-27 16:07:09 -07002145 mReminderMinuteValues, mReminderMinuteLabels, mReminderMethodValues,
2146 mReminderMethodLabels, ReminderEntry.valueOf(mDefaultReminderMinutes),
2147 mMaxReminders, mReminderChangeListener);
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002148 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002149
Sara Ting06f3d6d2012-03-23 17:19:22 -07002150 EventViewUtils.updateAddReminderButton(mView, mReminderViews, mMaxReminders);
2151 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002152
RoboErike35a0322011-09-01 16:21:49 -07002153 synchronized private void prepareReminders() {
2154 // Nothing to do if we've already built these lists _and_ we aren't
2155 // removing not allowed methods
2156 if (mReminderMinuteValues != null && mReminderMinuteLabels != null
2157 && mReminderMethodValues != null && mReminderMethodLabels != null
2158 && mCalendarAllowedReminders == null) {
2159 return;
2160 }
2161 // Load the labels and corresponding numeric values for the minutes and methods lists
2162 // from the assets. If we're switching calendars, we need to clear and re-populate the
2163 // lists (which may have elements added and removed based on calendar properties). This
2164 // is mostly relevant for "methods", since we shouldn't have any "minutes" values in a
2165 // new event that aren't in the default set.
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002166 Resources r = mActivity.getResources();
2167 mReminderMinuteValues = loadIntegerArray(r, R.array.reminder_minutes_values);
2168 mReminderMinuteLabels = loadStringArray(r, R.array.reminder_minutes_labels);
2169 mReminderMethodValues = loadIntegerArray(r, R.array.reminder_methods_values);
2170 mReminderMethodLabels = loadStringArray(r, R.array.reminder_methods_labels);
RoboErike35a0322011-09-01 16:21:49 -07002171
2172 // Remove any reminder methods that aren't allowed for this calendar. If this is
2173 // a new event, mCalendarAllowedReminders may not be set the first time we're called.
RoboErike35a0322011-09-01 16:21:49 -07002174 if (mCalendarAllowedReminders != null) {
2175 EventViewUtils.reduceMethodList(mReminderMethodValues, mReminderMethodLabels,
2176 mCalendarAllowedReminders);
2177 }
2178 if (mView != null) {
2179 mView.invalidate();
2180 }
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002181 }
2182
2183
2184 private boolean saveReminders() {
2185 ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(3);
2186
2187 // Read reminders from UI
2188 mReminders = EventViewUtils.reminderItemsToReminders(mReminderViews,
2189 mReminderMinuteValues, mReminderMethodValues);
RoboErike35a0322011-09-01 16:21:49 -07002190 mOriginalReminders.addAll(mUnsupportedReminders);
2191 Collections.sort(mOriginalReminders);
2192 mReminders.addAll(mUnsupportedReminders);
2193 Collections.sort(mReminders);
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002194
2195 // Check if there are any changes in the reminder
2196 boolean changed = EditEventHelper.saveReminders(ops, mEventId, mReminders,
2197 mOriginalReminders, false /* no force save */);
2198
2199 if (!changed) {
2200 return false;
2201 }
2202
2203 // save new reminders
2204 AsyncQueryService service = new AsyncQueryService(getActivity());
2205 service.startBatch(0, null, Calendars.CONTENT_URI.getAuthority(), ops, 0);
Sam Blitzstein9d4a9522012-10-17 14:39:38 -07002206 mOriginalReminders = mReminders;
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002207 // Update the "hasAlarm" field for the event
2208 Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId);
2209 int len = mReminders.size();
2210 boolean hasAlarm = len > 0;
2211 if (hasAlarm != mHasAlarm) {
2212 ContentValues values = new ContentValues();
2213 values.put(Events.HAS_ALARM, hasAlarm ? 1 : 0);
2214 service.startUpdate(0, null, uri, values, null, null, 0);
2215 }
2216 return true;
2217 }
2218
2219 /**
Sara Ting42896f72012-03-15 15:24:36 -07002220 * Email all the attendees of the event, except for the viewer (so as to not email
2221 * himself) and resources like conference rooms.
2222 */
2223 private void emailAttendees() {
Sara Ting7da27672012-07-24 16:23:53 -07002224 Intent i = new Intent(getActivity(), QuickResponseActivity.class);
2225 i.putExtra(QuickResponseActivity.EXTRA_EVENT_ID, mEventId);
2226 i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2227 startActivity(i);
Sara Ting42896f72012-03-15 15:24:36 -07002228 }
2229
2230 /**
Isaac Katzenelson1ce35aa2011-07-05 10:03:28 -07002231 * Loads an integer array asset into a list.
2232 */
2233 private static ArrayList<Integer> loadIntegerArray(Resources r, int resNum) {
2234 int[] vals = r.getIntArray(resNum);
2235 int size = vals.length;
2236 ArrayList<Integer> list = new ArrayList<Integer>(size);
2237
2238 for (int i = 0; i < size; i++) {
2239 list.add(vals[i]);
2240 }
2241
2242 return list;
2243 }
2244 /**
2245 * Loads a String array asset into a list.
2246 */
2247 private static ArrayList<String> loadStringArray(Resources r, int resNum) {
2248 String[] labels = r.getStringArray(resNum);
2249 ArrayList<String> list = new ArrayList<String>(Arrays.asList(labels));
2250 return list;
2251 }
2252
Michael Chan48bcc4c2012-12-12 11:38:16 -08002253 @Override
Isaac Katzenelsonb33cdf42011-10-14 18:15:18 -07002254 public void onDeleteStarted() {
2255 mEventDeletionStarted = true;
2256 }
2257
Isaac Katzenelsonb0a313a2011-10-24 11:41:56 -07002258 private Dialog.OnDismissListener createDeleteOnDismissListener() {
2259 return new Dialog.OnDismissListener() {
2260 @Override
2261 public void onDismiss(DialogInterface dialog) {
2262 // Since OnPause will force the dialog to dismiss , do
2263 // not change the dialog status
2264 if (!mIsPaused) {
2265 mDeleteDialogVisible = false;
2266 }
2267 }
2268 };
2269 }
2270
Isaac Katzenelson80d640f2012-04-20 09:21:28 -07002271 public long getEventId() {
2272 return mEventId;
2273 }
2274
2275 public long getStartMillis() {
2276 return mStartMillis;
2277 }
2278 public long getEndMillis() {
2279 return mEndMillis;
2280 }
Michael Chan363aa9c2012-05-17 10:31:32 -07002281 private void setDialogSize(Resources r) {
2282 mDialogWidth = (int)r.getDimension(R.dimen.event_info_dialog_width);
2283 mDialogHeight = (int)r.getDimension(R.dimen.event_info_dialog_height);
2284 }
James Kungb8904fb2013-02-14 14:37:42 -08002285
2286 @Override
2287 public void onColorSelected(int color) {
James Kung497a6252013-05-17 14:47:33 -07002288 mCurrentColor = color;
2289 mCurrentColorKey = mDisplayColorKeyMap.get(color);
2290 mHeadlines.setBackgroundColor(color);
James Kungb8904fb2013-02-14 14:37:42 -08002291 }
Mason Tang2bebde72010-08-04 17:20:24 -07002292}