Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package com.android.calendar; |
| 18 | |
Michael Chan | 2c8485c | 2012-05-09 10:23:45 -0700 | [diff] [blame^] | 19 | import static android.provider.CalendarContract.EXTRA_EVENT_ALL_DAY; |
| 20 | import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME; |
| 21 | import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME; |
| 22 | import static com.android.calendar.CalendarController.EVENT_EDIT_ON_LAUNCH; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 23 | |
Isaac Katzenelson | 8f4d969 | 2012-02-23 17:34:07 -0800 | [diff] [blame] | 24 | import android.animation.Animator; |
| 25 | import android.animation.AnimatorListenerAdapter; |
| 26 | import android.animation.ObjectAnimator; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 27 | import android.app.Activity; |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 28 | import android.app.Dialog; |
| 29 | import android.app.DialogFragment; |
Andy McFadden | ef31a98 | 2011-06-09 07:38:56 -0700 | [diff] [blame] | 30 | import android.app.Service; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 31 | import android.content.ActivityNotFoundException; |
Erik | 364309f | 2010-12-23 14:26:26 -0800 | [diff] [blame] | 32 | import android.content.ContentProviderOperation; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 33 | import android.content.ContentResolver; |
| 34 | import android.content.ContentUris; |
| 35 | import android.content.ContentValues; |
| 36 | import android.content.Context; |
Isaac Katzenelson | b0a313a | 2011-10-24 11:41:56 -0700 | [diff] [blame] | 37 | import android.content.DialogInterface; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 38 | import android.content.Intent; |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 39 | import android.content.SharedPreferences; |
Michael Chan | 2c8485c | 2012-05-09 10:23:45 -0700 | [diff] [blame^] | 40 | import android.content.pm.ApplicationInfo; |
| 41 | import android.content.pm.PackageManager; |
| 42 | import android.content.pm.PackageManager.NameNotFoundException; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 43 | import android.content.res.Resources; |
| 44 | import android.database.Cursor; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 45 | import android.graphics.Rect; |
Michael Chan | 71b221a | 2010-10-25 17:55:44 -0700 | [diff] [blame] | 46 | import android.graphics.Typeface; |
Michael Chan | 2c8485c | 2012-05-09 10:23:45 -0700 | [diff] [blame^] | 47 | import android.graphics.drawable.Drawable; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 48 | import android.net.Uri; |
| 49 | import android.os.Bundle; |
RoboErik | a7c0390 | 2011-06-14 11:06:44 -0700 | [diff] [blame] | 50 | import android.provider.CalendarContract; |
| 51 | import android.provider.CalendarContract.Attendees; |
| 52 | import android.provider.CalendarContract.Calendars; |
| 53 | import android.provider.CalendarContract.Events; |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 54 | import android.provider.CalendarContract.Reminders; |
Erik | cb81189 | 2010-09-28 13:44:19 -0700 | [diff] [blame] | 55 | import android.provider.ContactsContract; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 56 | import android.provider.ContactsContract.CommonDataKinds; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 57 | import android.provider.ContactsContract.Intents; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 58 | import android.provider.ContactsContract.QuickContact; |
Michael Chan | 8ce3b7d | 2010-09-01 15:41:01 -0700 | [diff] [blame] | 59 | import android.text.Spannable; |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 60 | import android.text.SpannableString; |
Michael Chan | 8ce3b7d | 2010-09-01 15:41:01 -0700 | [diff] [blame] | 61 | import android.text.SpannableStringBuilder; |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 62 | import android.text.Spanned; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 63 | import android.text.TextUtils; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 64 | import android.text.format.Time; |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 65 | import android.text.method.LinkMovementMethod; |
| 66 | import android.text.method.MovementMethod; |
Michael Chan | 8ce3b7d | 2010-09-01 15:41:01 -0700 | [diff] [blame] | 67 | import android.text.style.ForegroundColorSpan; |
Michael Chan | 71b221a | 2010-10-25 17:55:44 -0700 | [diff] [blame] | 68 | import android.text.style.StyleSpan; |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 69 | import android.text.style.URLSpan; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 70 | import android.text.util.Linkify; |
| 71 | import android.text.util.Rfc822Token; |
| 72 | import android.util.Log; |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 73 | import android.view.Gravity; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 74 | import android.view.LayoutInflater; |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 75 | import android.view.Menu; |
| 76 | import android.view.MenuInflater; |
| 77 | import android.view.MenuItem; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 78 | import android.view.MotionEvent; |
| 79 | import android.view.View; |
Erik | cb81189 | 2010-09-28 13:44:19 -0700 | [diff] [blame] | 80 | import android.view.View.OnClickListener; |
| 81 | import android.view.View.OnTouchListener; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 82 | import android.view.ViewGroup; |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 83 | import android.view.Window; |
| 84 | import android.view.WindowManager; |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 85 | import android.view.accessibility.AccessibilityEvent; |
| 86 | import android.view.accessibility.AccessibilityManager; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 87 | import android.widget.AdapterView; |
RoboErik | 8b5743c | 2011-09-27 16:07:09 -0700 | [diff] [blame] | 88 | import android.widget.AdapterView.OnItemSelectedListener; |
Michael Chan | 8ce3b7d | 2010-09-01 15:41:01 -0700 | [diff] [blame] | 89 | import android.widget.Button; |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 90 | import android.widget.LinearLayout; |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 91 | import android.widget.RadioButton; |
Michael Chan | f92f46b | 2010-10-27 18:59:05 -0700 | [diff] [blame] | 92 | import android.widget.RadioGroup; |
| 93 | import android.widget.RadioGroup.OnCheckedChangeListener; |
RoboErik | 8b5743c | 2011-09-27 16:07:09 -0700 | [diff] [blame] | 94 | import android.widget.ScrollView; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 95 | import android.widget.TextView; |
| 96 | import android.widget.Toast; |
| 97 | |
Michael Chan | 2c8485c | 2012-05-09 10:23:45 -0700 | [diff] [blame^] | 98 | import com.android.calendar.CalendarController.EventInfo; |
| 99 | import com.android.calendar.CalendarController.EventType; |
| 100 | import com.android.calendar.CalendarEventModel.Attendee; |
| 101 | import com.android.calendar.CalendarEventModel.ReminderEntry; |
| 102 | import com.android.calendar.event.AttendeesView; |
| 103 | import com.android.calendar.event.EditEventActivity; |
| 104 | import com.android.calendar.event.EditEventHelper; |
| 105 | import com.android.calendar.event.EventViewUtils; |
| 106 | import com.android.calendarcommon.EventRecurrence; |
| 107 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 108 | import java.util.ArrayList; |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 109 | import java.util.Arrays; |
| 110 | import java.util.Collections; |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 111 | import java.util.List; |
RoboErik | 8b5743c | 2011-09-27 16:07:09 -0700 | [diff] [blame] | 112 | import java.util.regex.Pattern; |
Isaac Katzenelson | f6f7977 | 2011-06-02 16:29:18 -0700 | [diff] [blame] | 113 | |
Michael Chan | f92f46b | 2010-10-27 18:59:05 -0700 | [diff] [blame] | 114 | public class EventInfoFragment extends DialogFragment implements OnCheckedChangeListener, |
Isaac Katzenelson | b33cdf4 | 2011-10-14 18:15:18 -0700 | [diff] [blame] | 115 | CalendarController.EventHandler, OnClickListener, DeleteEventHelper.DeleteNotifyListener { |
Michael Chan | 83efa2d | 2012-04-24 17:42:21 -0700 | [diff] [blame] | 116 | |
Erik | d845fbe | 2010-08-12 11:20:01 -0700 | [diff] [blame] | 117 | public static final boolean DEBUG = false; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 118 | |
Michael Chan | 2c7c851 | 2010-12-10 14:12:57 -0800 | [diff] [blame] | 119 | public static final String TAG = "EventInfoFragment"; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 120 | |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 121 | protected static final String BUNDLE_KEY_EVENT_ID = "key_event_id"; |
| 122 | protected static final String BUNDLE_KEY_START_MILLIS = "key_start_millis"; |
| 123 | protected static final String BUNDLE_KEY_END_MILLIS = "key_end_millis"; |
| 124 | protected static final String BUNDLE_KEY_IS_DIALOG = "key_fragment_is_dialog"; |
Isaac Katzenelson | b0a313a | 2011-10-24 11:41:56 -0700 | [diff] [blame] | 125 | protected static final String BUNDLE_KEY_DELETE_DIALOG_VISIBLE = "key_delete_dialog_visible"; |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 126 | protected static final String BUNDLE_KEY_WINDOW_STYLE = "key_window_style"; |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 127 | protected static final String BUNDLE_KEY_ATTENDEE_RESPONSE = "key_attendee_response"; |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 128 | |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 129 | private static final String PERIOD_SPACE = ". "; |
| 130 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 131 | /** |
| 132 | * These are the corresponding indices into the array of strings |
| 133 | * "R.array.change_response_labels" in the resource file. |
| 134 | */ |
| 135 | static final int UPDATE_SINGLE = 0; |
| 136 | static final int UPDATE_ALL = 1; |
| 137 | |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 138 | // Style of view |
| 139 | public static final int FULL_WINDOW_STYLE = 0; |
| 140 | public static final int DIALOG_WINDOW_STYLE = 1; |
| 141 | |
| 142 | private int mWindowStyle = DIALOG_WINDOW_STYLE; |
| 143 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 144 | // Query tokens for QueryHandler |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 145 | private static final int TOKEN_QUERY_EVENT = 1 << 0; |
| 146 | private static final int TOKEN_QUERY_CALENDARS = 1 << 1; |
| 147 | private static final int TOKEN_QUERY_ATTENDEES = 1 << 2; |
| 148 | private static final int TOKEN_QUERY_DUPLICATE_CALENDARS = 1 << 3; |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 149 | private static final int TOKEN_QUERY_REMINDERS = 1 << 4; |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 150 | private static final int TOKEN_QUERY_ALL = TOKEN_QUERY_DUPLICATE_CALENDARS |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 151 | | TOKEN_QUERY_ATTENDEES | TOKEN_QUERY_CALENDARS | TOKEN_QUERY_EVENT |
| 152 | | TOKEN_QUERY_REMINDERS; |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 153 | private int mCurrentQuery = 0; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 154 | |
| 155 | private static final String[] EVENT_PROJECTION = new String[] { |
| 156 | Events._ID, // 0 do not remove; used in DeleteEventHelper |
| 157 | Events.TITLE, // 1 do not remove; used in DeleteEventHelper |
| 158 | Events.RRULE, // 2 do not remove; used in DeleteEventHelper |
| 159 | Events.ALL_DAY, // 3 do not remove; used in DeleteEventHelper |
| 160 | Events.CALENDAR_ID, // 4 do not remove; used in DeleteEventHelper |
| 161 | Events.DTSTART, // 5 do not remove; used in DeleteEventHelper |
| 162 | Events._SYNC_ID, // 6 do not remove; used in DeleteEventHelper |
| 163 | Events.EVENT_TIMEZONE, // 7 do not remove; used in DeleteEventHelper |
| 164 | Events.DESCRIPTION, // 8 |
| 165 | Events.EVENT_LOCATION, // 9 |
RoboErik | ef2add9 | 2011-06-09 14:49:53 -0700 | [diff] [blame] | 166 | Calendars.CALENDAR_ACCESS_LEVEL, // 10 |
Alon Albert | a651f04 | 2012-03-01 15:25:53 -0800 | [diff] [blame] | 167 | Events.DISPLAY_COLOR, // 11 |
Michael Chan | 71b221a | 2010-10-25 17:55:44 -0700 | [diff] [blame] | 168 | Events.HAS_ATTENDEE_DATA, // 12 |
| 169 | Events.ORGANIZER, // 13 |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 170 | Events.HAS_ALARM, // 14 |
| 171 | Calendars.MAX_REMINDERS, //15 |
| 172 | Calendars.ALLOWED_REMINDERS, // 16 |
Michael Chan | 2c8485c | 2012-05-09 10:23:45 -0700 | [diff] [blame^] | 173 | Events.CUSTOM_APP_PACKAGE, // 17 |
| 174 | Events.CUSTOM_APP_URI, // 18 |
| 175 | Events.ORIGINAL_SYNC_ID, // 19 do not remove; used in DeleteEventHelper |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 176 | }; |
| 177 | private static final int EVENT_INDEX_ID = 0; |
| 178 | private static final int EVENT_INDEX_TITLE = 1; |
| 179 | private static final int EVENT_INDEX_RRULE = 2; |
| 180 | private static final int EVENT_INDEX_ALL_DAY = 3; |
| 181 | private static final int EVENT_INDEX_CALENDAR_ID = 4; |
| 182 | private static final int EVENT_INDEX_SYNC_ID = 6; |
| 183 | private static final int EVENT_INDEX_EVENT_TIMEZONE = 7; |
| 184 | private static final int EVENT_INDEX_DESCRIPTION = 8; |
| 185 | private static final int EVENT_INDEX_EVENT_LOCATION = 9; |
Michael Chan | 71b221a | 2010-10-25 17:55:44 -0700 | [diff] [blame] | 186 | private static final int EVENT_INDEX_ACCESS_LEVEL = 10; |
| 187 | private static final int EVENT_INDEX_COLOR = 11; |
| 188 | private static final int EVENT_INDEX_HAS_ATTENDEE_DATA = 12; |
| 189 | private static final int EVENT_INDEX_ORGANIZER = 13; |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 190 | private static final int EVENT_INDEX_HAS_ALARM = 14; |
| 191 | private static final int EVENT_INDEX_MAX_REMINDERS = 15; |
| 192 | private static final int EVENT_INDEX_ALLOWED_REMINDERS = 16; |
Michael Chan | 2c8485c | 2012-05-09 10:23:45 -0700 | [diff] [blame^] | 193 | private static final int EVENT_INDEX_CUSTOM_APP_PACKAGE = 17; |
| 194 | private static final int EVENT_INDEX_CUSTOM_APP_URI = 18; |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 195 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 196 | |
| 197 | private static final String[] ATTENDEES_PROJECTION = new String[] { |
| 198 | Attendees._ID, // 0 |
| 199 | Attendees.ATTENDEE_NAME, // 1 |
| 200 | Attendees.ATTENDEE_EMAIL, // 2 |
| 201 | Attendees.ATTENDEE_RELATIONSHIP, // 3 |
| 202 | Attendees.ATTENDEE_STATUS, // 4 |
Sara Ting | ddbc002 | 2012-04-26 17:08:46 -0700 | [diff] [blame] | 203 | Attendees.ATTENDEE_IDENTITY, // 5 |
| 204 | Attendees.ATTENDEE_ID_NAMESPACE // 6 |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 205 | }; |
| 206 | private static final int ATTENDEES_INDEX_ID = 0; |
| 207 | private static final int ATTENDEES_INDEX_NAME = 1; |
| 208 | private static final int ATTENDEES_INDEX_EMAIL = 2; |
| 209 | private static final int ATTENDEES_INDEX_RELATIONSHIP = 3; |
| 210 | private static final int ATTENDEES_INDEX_STATUS = 4; |
Sara Ting | ddbc002 | 2012-04-26 17:08:46 -0700 | [diff] [blame] | 211 | private static final int ATTENDEES_INDEX_IDENTITY = 5; |
| 212 | private static final int ATTENDEES_INDEX_ID_NAMESPACE = 6; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 213 | |
| 214 | private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=?"; |
| 215 | |
| 216 | private static final String ATTENDEES_SORT_ORDER = Attendees.ATTENDEE_NAME + " ASC, " |
| 217 | + Attendees.ATTENDEE_EMAIL + " ASC"; |
| 218 | |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 219 | private static final String[] REMINDERS_PROJECTION = new String[] { |
| 220 | Reminders._ID, // 0 |
| 221 | Reminders.MINUTES, // 1 |
| 222 | Reminders.METHOD // 2 |
| 223 | }; |
| 224 | private static final int REMINDERS_INDEX_ID = 0; |
| 225 | private static final int REMINDERS_MINUTES_ID = 1; |
| 226 | private static final int REMINDERS_METHOD_ID = 2; |
| 227 | |
| 228 | private static final String REMINDERS_WHERE = Reminders.EVENT_ID + "=?"; |
| 229 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 230 | static final String[] CALENDARS_PROJECTION = new String[] { |
| 231 | Calendars._ID, // 0 |
RoboErik | ef2add9 | 2011-06-09 14:49:53 -0700 | [diff] [blame] | 232 | Calendars.CALENDAR_DISPLAY_NAME, // 1 |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 233 | Calendars.OWNER_ACCOUNT, // 2 |
Sara Ting | 42896f7 | 2012-03-15 15:24:36 -0700 | [diff] [blame] | 234 | Calendars.CAN_ORGANIZER_RESPOND, // 3 |
| 235 | Calendars.ACCOUNT_NAME // 4 |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 236 | }; |
| 237 | static final int CALENDARS_INDEX_DISPLAY_NAME = 1; |
| 238 | static final int CALENDARS_INDEX_OWNER_ACCOUNT = 2; |
| 239 | static final int CALENDARS_INDEX_OWNER_CAN_RESPOND = 3; |
Sara Ting | 42896f7 | 2012-03-15 15:24:36 -0700 | [diff] [blame] | 240 | static final int CALENDARS_INDEX_ACCOUNT_NAME = 4; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 241 | |
| 242 | static final String CALENDARS_WHERE = Calendars._ID + "=?"; |
RoboErik | ef2add9 | 2011-06-09 14:49:53 -0700 | [diff] [blame] | 243 | static final String CALENDARS_DUPLICATE_NAME_WHERE = Calendars.CALENDAR_DISPLAY_NAME + "=?"; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 244 | |
Andy McFadden | fd8ce5e | 2011-11-15 15:44:57 -0800 | [diff] [blame] | 245 | private static final String NANP_ALLOWED_SYMBOLS = "()+-*#."; |
| 246 | private static final int NANP_MIN_DIGITS = 7; |
| 247 | private static final int NANP_MAX_DIGITS = 11; |
| 248 | |
| 249 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 250 | private View mView; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 251 | |
| 252 | private Uri mUri; |
| 253 | private long mEventId; |
| 254 | private Cursor mEventCursor; |
| 255 | private Cursor mAttendeesCursor; |
| 256 | private Cursor mCalendarsCursor; |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 257 | private Cursor mRemindersCursor; |
| 258 | |
Michael Chan | 0a01fd3 | 2011-01-23 15:13:28 -0800 | [diff] [blame] | 259 | private static float mScale = 0; // Used for supporting different screen densities |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 260 | |
Michael Chan | 2c8485c | 2012-05-09 10:23:45 -0700 | [diff] [blame^] | 261 | private static int mCustomAppIconSize = 32; |
| 262 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 263 | private long mStartMillis; |
| 264 | private long mEndMillis; |
Michael Chan | 8b1119b | 2012-01-06 16:04:55 -0800 | [diff] [blame] | 265 | private boolean mAllDay; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 266 | |
| 267 | private boolean mHasAttendeeData; |
Michael Chan | 83efa2d | 2012-04-24 17:42:21 -0700 | [diff] [blame] | 268 | private String mEventOrganizerEmail; |
| 269 | private String mEventOrganizerDisplayName = ""; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 270 | private boolean mIsOrganizer; |
Erik | d845fbe | 2010-08-12 11:20:01 -0700 | [diff] [blame] | 271 | private long mCalendarOwnerAttendeeId = EditEventHelper.ATTENDEE_ID_NONE; |
Michael Chan | 352e1a2 | 2010-09-28 05:15:08 -0700 | [diff] [blame] | 272 | private boolean mOwnerCanRespond; |
Sara Ting | 42896f7 | 2012-03-15 15:24:36 -0700 | [diff] [blame] | 273 | private String mSyncAccountName; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 274 | private String mCalendarOwnerAccount; |
| 275 | private boolean mCanModifyCalendar; |
RoboErik | 65eeb79 | 2011-08-08 12:54:00 -0700 | [diff] [blame] | 276 | private boolean mCanModifyEvent; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 277 | private boolean mIsBusyFreeCalendar; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 278 | private int mNumOfAttendees; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 279 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 280 | private EditResponseHelper mEditResponseHelper; |
Isaac Katzenelson | b0a313a | 2011-10-24 11:41:56 -0700 | [diff] [blame] | 281 | private boolean mDeleteDialogVisible = false; |
| 282 | private DeleteEventHelper mDeleteHelper; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 283 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 284 | private int mOriginalAttendeeResponse; |
Isaac Katzenelson | 6bcafcf | 2012-05-02 18:25:36 -0700 | [diff] [blame] | 285 | private int mAttendeeResponseFromIntent = Attendees.ATTENDEE_STATUS_NONE; |
| 286 | private int mUserSetResponse = Attendees.ATTENDEE_STATUS_NONE; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 287 | private boolean mIsRepeating; |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 288 | private boolean mHasAlarm; |
| 289 | private int mMaxReminders; |
| 290 | private String mCalendarAllowedReminders; |
Isaac Katzenelson | b33cdf4 | 2011-10-14 18:15:18 -0700 | [diff] [blame] | 291 | // Used to prevent saving changes in event if it is being deleted. |
| 292 | private boolean mEventDeletionStarted = false; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 293 | |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 294 | private TextView mTitle; |
Sara Ting | 75f5366 | 2012-04-09 15:37:10 -0700 | [diff] [blame] | 295 | private TextView mWhenDateTime; |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 296 | private TextView mWhere; |
Michael Chan | 99704a2 | 2011-11-11 10:24:37 -0800 | [diff] [blame] | 297 | private ExpandableTextView mDesc; |
Isaac Katzenelson | c0624ee | 2011-06-03 09:24:27 -0700 | [diff] [blame] | 298 | private AttendeesView mLongAttendees; |
RoboErik | d8353fb | 2011-07-21 11:28:11 -0700 | [diff] [blame] | 299 | private Menu mMenu = null; |
Isaac Katzenelson | fae6d5c | 2011-06-16 15:43:41 -0700 | [diff] [blame] | 300 | private View mHeadlines; |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 301 | private ScrollView mScrollView; |
Isaac Katzenelson | 8f4d969 | 2012-02-23 17:34:07 -0800 | [diff] [blame] | 302 | private View mLoadingMsgView; |
| 303 | private ObjectAnimator mAnimateAlpha; |
Isaac Katzenelson | 263b029 | 2012-03-14 14:55:50 -0700 | [diff] [blame] | 304 | private long mLoadingMsgStartTime; |
Isaac Katzenelson | 8f4d969 | 2012-02-23 17:34:07 -0800 | [diff] [blame] | 305 | private static final int FADE_IN_TIME = 300; // in milliseconds |
Isaac Katzenelson | 263b029 | 2012-03-14 14:55:50 -0700 | [diff] [blame] | 306 | private static final int LOADING_MSG_DELAY = 600; // in milliseconds |
| 307 | private static final int LOADING_MSG_MIN_DISPLAY_TIME = 600; |
Isaac Katzenelson | 80d640f | 2012-04-20 09:21:28 -0700 | [diff] [blame] | 308 | private boolean mNoCrossFade = false; // Used to prevent repeated cross-fade |
Isaac Katzenelson | 8f4d969 | 2012-02-23 17:34:07 -0800 | [diff] [blame] | 309 | |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 310 | |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 311 | private static final Pattern mWildcardPattern = Pattern.compile("^.*$"); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 312 | |
| 313 | ArrayList<Attendee> mAcceptedAttendees = new ArrayList<Attendee>(); |
| 314 | ArrayList<Attendee> mDeclinedAttendees = new ArrayList<Attendee>(); |
| 315 | ArrayList<Attendee> mTentativeAttendees = new ArrayList<Attendee>(); |
| 316 | ArrayList<Attendee> mNoResponseAttendees = new ArrayList<Attendee>(); |
Sara Ting | cb5f568 | 2012-04-04 22:52:20 -0700 | [diff] [blame] | 317 | ArrayList<String> mToEmails = new ArrayList<String>(); |
| 318 | ArrayList<String> mCcEmails = new ArrayList<String>(); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 319 | private int mColor; |
| 320 | |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 321 | |
| 322 | private int mDefaultReminderMinutes; |
Isaac Katzenelson | ac4350b | 2012-04-18 15:33:26 -0700 | [diff] [blame] | 323 | private final ArrayList<LinearLayout> mReminderViews = new ArrayList<LinearLayout>(0); |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 324 | public ArrayList<ReminderEntry> mReminders; |
RoboErik | 7f078b7 | 2011-09-06 10:25:31 -0700 | [diff] [blame] | 325 | public ArrayList<ReminderEntry> mOriginalReminders = new ArrayList<ReminderEntry>(); |
| 326 | public ArrayList<ReminderEntry> mUnsupportedReminders = new ArrayList<ReminderEntry>(); |
RoboErik | 8b5743c | 2011-09-27 16:07:09 -0700 | [diff] [blame] | 327 | private boolean mUserModifiedReminders = false; |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 328 | |
| 329 | /** |
| 330 | * Contents of the "minutes" spinner. This has default values from the XML file, augmented |
| 331 | * with any additional values that were already associated with the event. |
| 332 | */ |
| 333 | private ArrayList<Integer> mReminderMinuteValues; |
| 334 | private ArrayList<String> mReminderMinuteLabels; |
| 335 | |
| 336 | /** |
| 337 | * Contents of the "methods" spinner. The "values" list specifies the method constant |
| 338 | * (e.g. {@link Reminders#METHOD_ALERT}) associated with the labels. Any methods that |
| 339 | * aren't allowed by the Calendar will be removed. |
| 340 | */ |
| 341 | private ArrayList<Integer> mReminderMethodValues; |
| 342 | private ArrayList<String> mReminderMethodLabels; |
| 343 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 344 | private QueryHandler mHandler; |
| 345 | |
Isaac Katzenelson | b33cdf4 | 2011-10-14 18:15:18 -0700 | [diff] [blame] | 346 | |
Isaac Katzenelson | ac4350b | 2012-04-18 15:33:26 -0700 | [diff] [blame] | 347 | private final Runnable mTZUpdater = new Runnable() { |
Erik | cb81189 | 2010-09-28 13:44:19 -0700 | [diff] [blame] | 348 | @Override |
| 349 | public void run() { |
| 350 | updateEvent(mView); |
| 351 | } |
| 352 | }; |
| 353 | |
Isaac Katzenelson | ac4350b | 2012-04-18 15:33:26 -0700 | [diff] [blame] | 354 | private final Runnable mLoadingMsgAlphaUpdater = new Runnable() { |
Isaac Katzenelson | 263b029 | 2012-03-14 14:55:50 -0700 | [diff] [blame] | 355 | @Override |
| 356 | public void run() { |
| 357 | // Since this is run after a delay, make sure to only show the message |
| 358 | // if the event's data is not shown yet. |
| 359 | if (!mAnimateAlpha.isRunning() && mScrollView.getAlpha() == 0) { |
| 360 | mLoadingMsgStartTime = System.currentTimeMillis(); |
| 361 | mLoadingMsgView.setAlpha(1); |
| 362 | } |
| 363 | } |
| 364 | }; |
| 365 | |
RoboErik | 8b5743c | 2011-09-27 16:07:09 -0700 | [diff] [blame] | 366 | private OnItemSelectedListener mReminderChangeListener; |
| 367 | |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 368 | private static int mDialogWidth = 500; |
| 369 | private static int mDialogHeight = 600; |
Isaac Katzenelson | 0aa0c61 | 2011-10-03 16:46:10 -0700 | [diff] [blame] | 370 | private static int DIALOG_TOP_MARGIN = 8; |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 371 | private boolean mIsDialog = false; |
RoboErik | 7c6236d | 2011-02-24 16:41:18 -0800 | [diff] [blame] | 372 | private boolean mIsPaused = true; |
| 373 | private boolean mDismissOnResume = false; |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 374 | private int mX = -1; |
| 375 | private int mY = -1; |
Isaac Katzenelson | 0aa0c61 | 2011-10-03 16:46:10 -0700 | [diff] [blame] | 376 | private int mMinTop; // Dialog cannot be above this location |
Isaac Katzenelson | 10b6021 | 2011-06-28 17:59:14 -0700 | [diff] [blame] | 377 | private boolean mIsTabletConfig; |
| 378 | private Activity mActivity; |
Michael Chan | be2a432 | 2011-08-11 13:39:14 -0700 | [diff] [blame] | 379 | private Context mContext; |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 380 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 381 | private class QueryHandler extends AsyncQueryService { |
| 382 | public QueryHandler(Context context) { |
| 383 | super(context); |
| 384 | } |
| 385 | |
| 386 | @Override |
| 387 | protected void onQueryComplete(int token, Object cookie, Cursor cursor) { |
Mason Tang | 4003d1c | 2010-08-17 13:50:45 -0700 | [diff] [blame] | 388 | // if the activity is finishing, then close the cursor and return |
| 389 | final Activity activity = getActivity(); |
| 390 | if (activity == null || activity.isFinishing()) { |
| 391 | cursor.close(); |
| 392 | return; |
| 393 | } |
| 394 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 395 | switch (token) { |
| 396 | case TOKEN_QUERY_EVENT: |
| 397 | mEventCursor = Utils.matrixCursorFromCursor(cursor); |
| 398 | if (initEventCursor()) { |
| 399 | // The cursor is empty. This can happen if the event was |
| 400 | // deleted. |
| 401 | // FRAG_TODO we should no longer rely on Activity.finish() |
Mason Tang | 1df2ca6 | 2010-08-18 16:10:25 -0700 | [diff] [blame] | 402 | activity.finish(); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 403 | return; |
| 404 | } |
| 405 | updateEvent(mView); |
RoboErik | e35a032 | 2011-09-01 16:21:49 -0700 | [diff] [blame] | 406 | prepareReminders(); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 407 | |
| 408 | // start calendar query |
| 409 | Uri uri = Calendars.CONTENT_URI; |
| 410 | String[] args = new String[] { |
| 411 | Long.toString(mEventCursor.getLong(EVENT_INDEX_CALENDAR_ID))}; |
| 412 | startQuery(TOKEN_QUERY_CALENDARS, null, uri, CALENDARS_PROJECTION, |
| 413 | CALENDARS_WHERE, args, null); |
| 414 | break; |
| 415 | case TOKEN_QUERY_CALENDARS: |
| 416 | mCalendarsCursor = Utils.matrixCursorFromCursor(cursor); |
| 417 | updateCalendar(mView); |
Mason Tang | 4003d1c | 2010-08-17 13:50:45 -0700 | [diff] [blame] | 418 | // FRAG_TODO fragments shouldn't set the title anymore |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 419 | updateTitle(); |
| 420 | |
Michael Chan | 352e1a2 | 2010-09-28 05:15:08 -0700 | [diff] [blame] | 421 | if (!mIsBusyFreeCalendar) { |
Michael Chan | 352e1a2 | 2010-09-28 05:15:08 -0700 | [diff] [blame] | 422 | args = new String[] { Long.toString(mEventId) }; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 423 | |
Michael Chan | 352e1a2 | 2010-09-28 05:15:08 -0700 | [diff] [blame] | 424 | // start attendees query |
| 425 | uri = Attendees.CONTENT_URI; |
| 426 | startQuery(TOKEN_QUERY_ATTENDEES, null, uri, ATTENDEES_PROJECTION, |
| 427 | ATTENDEES_WHERE, args, ATTENDEES_SORT_ORDER); |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 428 | } else { |
| 429 | sendAccessibilityEventIfQueryDone(TOKEN_QUERY_ATTENDEES); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 430 | } |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 431 | if (mHasAlarm) { |
| 432 | // start reminders query |
| 433 | args = new String[] { Long.toString(mEventId) }; |
| 434 | uri = Reminders.CONTENT_URI; |
| 435 | startQuery(TOKEN_QUERY_REMINDERS, null, uri, |
| 436 | REMINDERS_PROJECTION, REMINDERS_WHERE, args, null); |
| 437 | } else { |
| 438 | sendAccessibilityEventIfQueryDone(TOKEN_QUERY_REMINDERS); |
| 439 | } |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 440 | break; |
| 441 | case TOKEN_QUERY_ATTENDEES: |
| 442 | mAttendeesCursor = Utils.matrixCursorFromCursor(cursor); |
| 443 | initAttendeesCursor(mView); |
| 444 | updateResponse(mView); |
| 445 | break; |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 446 | case TOKEN_QUERY_REMINDERS: |
| 447 | mRemindersCursor = Utils.matrixCursorFromCursor(cursor); |
| 448 | initReminders(mView, mRemindersCursor); |
| 449 | break; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 450 | case TOKEN_QUERY_DUPLICATE_CALENDARS: |
Michael Chan | 71b221a | 2010-10-25 17:55:44 -0700 | [diff] [blame] | 451 | Resources res = activity.getResources(); |
| 452 | SpannableStringBuilder sb = new SpannableStringBuilder(); |
| 453 | |
| 454 | // Label |
| 455 | String label = res.getString(R.string.view_event_calendar_label); |
| 456 | sb.append(label).append(" "); |
| 457 | sb.setSpan(new StyleSpan(Typeface.BOLD), 0, label.length(), |
| 458 | Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| 459 | |
| 460 | // Calendar display name |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 461 | String calendarName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME); |
Michael Chan | 71b221a | 2010-10-25 17:55:44 -0700 | [diff] [blame] | 462 | sb.append(calendarName); |
| 463 | |
| 464 | // Show email account if display name is not unique and |
| 465 | // display name != email |
| 466 | String email = mCalendarsCursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT); |
| 467 | if (cursor.getCount() > 1 && !calendarName.equalsIgnoreCase(email)) { |
| 468 | sb.append(" (").append(email).append(")"); |
| 469 | } |
| 470 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 471 | break; |
| 472 | } |
| 473 | cursor.close(); |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 474 | sendAccessibilityEventIfQueryDone(token); |
Isaac Katzenelson | 263b029 | 2012-03-14 14:55:50 -0700 | [diff] [blame] | 475 | // All queries are done, show the view |
| 476 | if (mCurrentQuery == TOKEN_QUERY_ALL) { |
| 477 | if (mLoadingMsgView.getAlpha() == 1) { |
| 478 | // Loading message is showing, let it stay a bit more (to prevent |
| 479 | // flashing) by adding a start delay to the event animation |
| 480 | long timeDiff = LOADING_MSG_MIN_DISPLAY_TIME - (System.currentTimeMillis() - |
| 481 | mLoadingMsgStartTime); |
| 482 | if (timeDiff > 0) { |
| 483 | mAnimateAlpha.setStartDelay(timeDiff); |
| 484 | } |
| 485 | } |
Isaac Katzenelson | 80d640f | 2012-04-20 09:21:28 -0700 | [diff] [blame] | 486 | if (!mAnimateAlpha.isRunning() &&!mAnimateAlpha.isStarted() && !mNoCrossFade) { |
| 487 | mAnimateAlpha.start(); |
| 488 | } else { |
| 489 | mScrollView.setAlpha(1); |
| 490 | mLoadingMsgView.setVisibility(View.GONE); |
| 491 | } |
Isaac Katzenelson | 263b029 | 2012-03-14 14:55:50 -0700 | [diff] [blame] | 492 | } |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 493 | } |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 494 | } |
| 495 | |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 496 | private void sendAccessibilityEventIfQueryDone(int token) { |
| 497 | mCurrentQuery |= token; |
| 498 | if (mCurrentQuery == TOKEN_QUERY_ALL) { |
| 499 | sendAccessibilityEvent(); |
| 500 | } |
| 501 | } |
| 502 | |
Michael Chan | 0a01fd3 | 2011-01-23 15:13:28 -0800 | [diff] [blame] | 503 | public EventInfoFragment(Context context, Uri uri, long startMillis, long endMillis, |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 504 | int attendeeResponse, boolean isDialog, int windowStyle) { |
| 505 | |
Michael Chan | 2c8485c | 2012-05-09 10:23:45 -0700 | [diff] [blame^] | 506 | Resources r = context.getResources(); |
| 507 | if (mScale == 0) { |
| 508 | mScale = context.getResources().getDisplayMetrics().density; |
| 509 | if (mScale != 1) { |
| 510 | mCustomAppIconSize *= mScale; |
| 511 | if (isDialog) { |
Isaac Katzenelson | 65aba6a | 2012-04-27 15:57:04 -0700 | [diff] [blame] | 512 | mDialogWidth = r.getInteger(R.integer.event_info_dialog_width); |
| 513 | mDialogHeight = r.getInteger(R.integer.event_info_dialog_height); |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 514 | mDialogWidth *= mScale; |
| 515 | mDialogHeight *= mScale; |
| 516 | DIALOG_TOP_MARGIN *= mScale; |
| 517 | } |
Michael Chan | 0a01fd3 | 2011-01-23 15:13:28 -0800 | [diff] [blame] | 518 | } |
| 519 | } |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 520 | mIsDialog = isDialog; |
Isaac Katzenelson | c0624ee | 2011-06-03 09:24:27 -0700 | [diff] [blame] | 521 | |
Michael Chan | 2fc6b79 | 2011-01-26 17:12:44 -0800 | [diff] [blame] | 522 | setStyle(DialogFragment.STYLE_NO_TITLE, 0); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 523 | mUri = uri; |
| 524 | mStartMillis = startMillis; |
| 525 | mEndMillis = endMillis; |
| 526 | mAttendeeResponseFromIntent = attendeeResponse; |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 527 | mWindowStyle = windowStyle; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 528 | } |
| 529 | |
Andy McFadden | ef31a98 | 2011-06-09 07:38:56 -0700 | [diff] [blame] | 530 | // This is currently required by the fragment manager. |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 531 | public EventInfoFragment() { |
| 532 | } |
| 533 | |
| 534 | |
| 535 | |
Michael Chan | 0a01fd3 | 2011-01-23 15:13:28 -0800 | [diff] [blame] | 536 | public EventInfoFragment(Context context, long eventId, long startMillis, long endMillis, |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 537 | int attendeeResponse, boolean isDialog, int windowStyle) { |
Michael Chan | 0a01fd3 | 2011-01-23 15:13:28 -0800 | [diff] [blame] | 538 | this(context, ContentUris.withAppendedId(Events.CONTENT_URI, eventId), startMillis, |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 539 | endMillis, attendeeResponse, isDialog, windowStyle); |
Mason Tang | 4003d1c | 2010-08-17 13:50:45 -0700 | [diff] [blame] | 540 | mEventId = eventId; |
| 541 | } |
| 542 | |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 543 | @Override |
| 544 | public void onActivityCreated(Bundle savedInstanceState) { |
| 545 | super.onActivityCreated(savedInstanceState); |
| 546 | |
RoboErik | 8b5743c | 2011-09-27 16:07:09 -0700 | [diff] [blame] | 547 | mReminderChangeListener = new OnItemSelectedListener() { |
| 548 | @Override |
| 549 | public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { |
| 550 | Integer prevValue = (Integer) parent.getTag(); |
| 551 | if (prevValue == null || prevValue != position) { |
| 552 | parent.setTag(position); |
| 553 | mUserModifiedReminders = true; |
| 554 | } |
| 555 | } |
| 556 | |
| 557 | @Override |
| 558 | public void onNothingSelected(AdapterView<?> parent) { |
| 559 | // do nothing |
| 560 | } |
| 561 | |
| 562 | }; |
| 563 | |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 564 | if (savedInstanceState != null) { |
| 565 | mIsDialog = savedInstanceState.getBoolean(BUNDLE_KEY_IS_DIALOG, false); |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 566 | mWindowStyle = savedInstanceState.getInt(BUNDLE_KEY_WINDOW_STYLE, |
| 567 | DIALOG_WINDOW_STYLE); |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 568 | } |
| 569 | |
| 570 | if (mIsDialog) { |
| 571 | applyDialogParams(); |
| 572 | } |
Michael Chan | 825b8ca | 2011-09-07 10:52:18 -0700 | [diff] [blame] | 573 | mContext = getActivity(); |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 574 | } |
| 575 | |
| 576 | private void applyDialogParams() { |
| 577 | Dialog dialog = getDialog(); |
| 578 | dialog.setCanceledOnTouchOutside(true); |
| 579 | |
| 580 | Window window = dialog.getWindow(); |
| 581 | window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); |
| 582 | |
| 583 | WindowManager.LayoutParams a = window.getAttributes(); |
| 584 | a.dimAmount = .4f; |
| 585 | |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 586 | a.width = mDialogWidth; |
| 587 | a.height = mDialogHeight; |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 588 | |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 589 | |
Isaac Katzenelson | 0b1bd10 | 2011-04-07 14:26:29 -0700 | [diff] [blame] | 590 | // On tablets , do smart positioning of dialog |
| 591 | // On phones , use the whole screen |
| 592 | |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 593 | if (mX != -1 || mY != -1) { |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 594 | a.x = mX - mDialogWidth / 2; |
| 595 | a.y = mY - mDialogHeight / 2; |
Isaac Katzenelson | 0aa0c61 | 2011-10-03 16:46:10 -0700 | [diff] [blame] | 596 | if (a.y < mMinTop) { |
| 597 | a.y = mMinTop + DIALOG_TOP_MARGIN; |
Isaac Katzenelson | 0b1bd10 | 2011-04-07 14:26:29 -0700 | [diff] [blame] | 598 | } |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 599 | a.gravity = Gravity.LEFT | Gravity.TOP; |
Isaac Katzenelson | 0b1bd10 | 2011-04-07 14:26:29 -0700 | [diff] [blame] | 600 | } |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 601 | window.setAttributes(a); |
| 602 | } |
| 603 | |
Isaac Katzenelson | 0aa0c61 | 2011-10-03 16:46:10 -0700 | [diff] [blame] | 604 | public void setDialogParams(int x, int y, int minTop) { |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 605 | mX = x; |
| 606 | mY = y; |
Isaac Katzenelson | 0aa0c61 | 2011-10-03 16:46:10 -0700 | [diff] [blame] | 607 | mMinTop = minTop; |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 608 | } |
| 609 | |
Michael Chan | f92f46b | 2010-10-27 18:59:05 -0700 | [diff] [blame] | 610 | // Implements OnCheckedChangeListener |
| 611 | @Override |
| 612 | public void onCheckedChanged(RadioGroup group, int checkedId) { |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 613 | // If this is not a repeating event, then don't display the dialog |
| 614 | // asking which events to change. |
RoboErik | 5afc083 | 2011-09-27 14:14:09 -0700 | [diff] [blame] | 615 | mUserSetResponse = getResponseFromButtonId(checkedId); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 616 | if (!mIsRepeating) { |
| 617 | return; |
| 618 | } |
| 619 | |
| 620 | // If the selection is the same as the original, then don't display the |
| 621 | // dialog asking which events to change. |
Michael Chan | f92f46b | 2010-10-27 18:59:05 -0700 | [diff] [blame] | 622 | if (checkedId == findButtonIdForResponse(mOriginalAttendeeResponse)) { |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 623 | return; |
| 624 | } |
| 625 | |
| 626 | // This is a repeating event. We need to ask the user if they mean to |
| 627 | // change just this one instance or all instances. |
| 628 | mEditResponseHelper.showDialog(mEditResponseHelper.getWhichEvents()); |
| 629 | } |
| 630 | |
| 631 | public void onNothingSelected(AdapterView<?> parent) { |
| 632 | } |
| 633 | |
| 634 | @Override |
| 635 | public void onAttach(Activity activity) { |
| 636 | super.onAttach(activity); |
Isaac Katzenelson | 10b6021 | 2011-06-28 17:59:14 -0700 | [diff] [blame] | 637 | mActivity = activity; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 638 | mEditResponseHelper = new EditResponseHelper(activity); |
RoboErik | 86550ce | 2011-08-22 16:47:51 -0700 | [diff] [blame] | 639 | |
| 640 | if (mAttendeeResponseFromIntent != Attendees.ATTENDEE_STATUS_NONE) { |
| 641 | mEditResponseHelper.setWhichEvents(UPDATE_ALL); |
| 642 | } |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 643 | mHandler = new QueryHandler(activity); |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 644 | if (!mIsDialog) { |
| 645 | setHasOptionsMenu(true); |
| 646 | } |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 647 | } |
| 648 | |
| 649 | @Override |
| 650 | public View onCreateView(LayoutInflater inflater, ViewGroup container, |
| 651 | Bundle savedInstanceState) { |
Isaac Katzenelson | 320c1b1 | 2011-11-07 15:31:45 -0800 | [diff] [blame] | 652 | |
| 653 | if (savedInstanceState != null) { |
| 654 | mIsDialog = savedInstanceState.getBoolean(BUNDLE_KEY_IS_DIALOG, false); |
| 655 | mWindowStyle = savedInstanceState.getInt(BUNDLE_KEY_WINDOW_STYLE, |
| 656 | DIALOG_WINDOW_STYLE); |
| 657 | mDeleteDialogVisible = |
| 658 | savedInstanceState.getBoolean(BUNDLE_KEY_DELETE_DIALOG_VISIBLE,false); |
| 659 | |
| 660 | } |
| 661 | |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 662 | if (mWindowStyle == DIALOG_WINDOW_STYLE) { |
Michael Chan | cba7f1f | 2011-11-07 17:05:59 -0800 | [diff] [blame] | 663 | mView = inflater.inflate(R.layout.event_info_dialog, container, false); |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 664 | } else { |
| 665 | mView = inflater.inflate(R.layout.event_info, container, false); |
| 666 | } |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 667 | mScrollView = (ScrollView) mView.findViewById(R.id.event_info_scroll_view); |
Isaac Katzenelson | 8f4d969 | 2012-02-23 17:34:07 -0800 | [diff] [blame] | 668 | mLoadingMsgView = mView.findViewById(R.id.event_info_loading_msg); |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 669 | mTitle = (TextView) mView.findViewById(R.id.title); |
Sara Ting | 75f5366 | 2012-04-09 15:37:10 -0700 | [diff] [blame] | 670 | mWhenDateTime = (TextView) mView.findViewById(R.id.when_datetime); |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 671 | mWhere = (TextView) mView.findViewById(R.id.where); |
Michael Chan | 99704a2 | 2011-11-11 10:24:37 -0800 | [diff] [blame] | 672 | mDesc = (ExpandableTextView) mView.findViewById(R.id.description); |
Isaac Katzenelson | fae6d5c | 2011-06-16 15:43:41 -0700 | [diff] [blame] | 673 | mHeadlines = mView.findViewById(R.id.event_info_headline); |
Isaac Katzenelson | c0624ee | 2011-06-03 09:24:27 -0700 | [diff] [blame] | 674 | mLongAttendees = (AttendeesView)mView.findViewById(R.id.long_attendee_list); |
Isaac Katzenelson | 10b6021 | 2011-06-28 17:59:14 -0700 | [diff] [blame] | 675 | mIsTabletConfig = Utils.getConfigBool(mActivity, R.bool.tablet_config); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 676 | |
Mason Tang | 4003d1c | 2010-08-17 13:50:45 -0700 | [diff] [blame] | 677 | if (mUri == null) { |
| 678 | // restore event ID from bundle |
| 679 | mEventId = savedInstanceState.getLong(BUNDLE_KEY_EVENT_ID); |
| 680 | mUri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId); |
| 681 | mStartMillis = savedInstanceState.getLong(BUNDLE_KEY_START_MILLIS); |
| 682 | mEndMillis = savedInstanceState.getLong(BUNDLE_KEY_END_MILLIS); |
| 683 | } |
| 684 | |
Isaac Katzenelson | 8f4d969 | 2012-02-23 17:34:07 -0800 | [diff] [blame] | 685 | mAnimateAlpha = ObjectAnimator.ofFloat(mScrollView, "Alpha", 0, 1); |
| 686 | mAnimateAlpha.setDuration(FADE_IN_TIME); |
| 687 | mAnimateAlpha.addListener(new AnimatorListenerAdapter() { |
| 688 | int defLayerType; |
| 689 | |
| 690 | @Override |
| 691 | public void onAnimationStart(Animator animation) { |
| 692 | // Use hardware layer for better performance during animation |
| 693 | defLayerType = mScrollView.getLayerType(); |
| 694 | mScrollView.setLayerType(View.LAYER_TYPE_HARDWARE, null); |
| 695 | // Ensure that the loading message is gone before showing the |
| 696 | // event info |
Isaac Katzenelson | 263b029 | 2012-03-14 14:55:50 -0700 | [diff] [blame] | 697 | mLoadingMsgView.removeCallbacks(mLoadingMsgAlphaUpdater); |
Isaac Katzenelson | 8f4d969 | 2012-02-23 17:34:07 -0800 | [diff] [blame] | 698 | mLoadingMsgView.setVisibility(View.GONE); |
| 699 | } |
| 700 | |
| 701 | @Override |
| 702 | public void onAnimationCancel(Animator animation) { |
| 703 | mScrollView.setLayerType(defLayerType, null); |
| 704 | } |
| 705 | |
| 706 | @Override |
| 707 | public void onAnimationEnd(Animator animation) { |
| 708 | mScrollView.setLayerType(defLayerType, null); |
Isaac Katzenelson | 80d640f | 2012-04-20 09:21:28 -0700 | [diff] [blame] | 709 | // Do not cross fade after the first time |
| 710 | mNoCrossFade = true; |
Isaac Katzenelson | 8f4d969 | 2012-02-23 17:34:07 -0800 | [diff] [blame] | 711 | } |
| 712 | }); |
| 713 | |
Isaac Katzenelson | 8f4d969 | 2012-02-23 17:34:07 -0800 | [diff] [blame] | 714 | mLoadingMsgView.setAlpha(0); |
| 715 | mScrollView.setAlpha(0); |
Isaac Katzenelson | 263b029 | 2012-03-14 14:55:50 -0700 | [diff] [blame] | 716 | mLoadingMsgView.postDelayed(mLoadingMsgAlphaUpdater, LOADING_MSG_DELAY); |
Isaac Katzenelson | 8f4d969 | 2012-02-23 17:34:07 -0800 | [diff] [blame] | 717 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 718 | // start loading the data |
Isaac Katzenelson | 8f4d969 | 2012-02-23 17:34:07 -0800 | [diff] [blame] | 719 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 720 | mHandler.startQuery(TOKEN_QUERY_EVENT, null, mUri, EVENT_PROJECTION, |
| 721 | null, null, null); |
| 722 | |
Erik | 89ad082 | 2011-01-18 15:55:17 -0800 | [diff] [blame] | 723 | Button b = (Button) mView.findViewById(R.id.delete); |
Michael Chan | 8ce3b7d | 2010-09-01 15:41:01 -0700 | [diff] [blame] | 724 | b.setOnClickListener(new OnClickListener() { |
| 725 | @Override |
| 726 | public void onClick(View v) { |
RoboErik | 69be855 | 2011-02-14 16:51:59 -0800 | [diff] [blame] | 727 | if (!mCanModifyCalendar) { |
| 728 | return; |
| 729 | } |
Isaac Katzenelson | b0a313a | 2011-10-24 11:41:56 -0700 | [diff] [blame] | 730 | mDeleteHelper = new DeleteEventHelper( |
Michael Chan | be2a432 | 2011-08-11 13:39:14 -0700 | [diff] [blame] | 731 | mContext, mActivity, |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 732 | !mIsDialog && !mIsTabletConfig /* exitWhenDone */); |
Isaac Katzenelson | b0a313a | 2011-10-24 11:41:56 -0700 | [diff] [blame] | 733 | mDeleteHelper.setDeleteNotificationListener(EventInfoFragment.this); |
| 734 | mDeleteHelper.setOnDismissListener(createDeleteOnDismissListener()); |
| 735 | mDeleteDialogVisible = true; |
| 736 | mDeleteHelper.delete(mStartMillis, mEndMillis, mEventId, -1, onDeleteRunnable); |
Michael Chan | 8ce3b7d | 2010-09-01 15:41:01 -0700 | [diff] [blame] | 737 | }}); |
| 738 | |
Isaac Katzenelson | 10b6021 | 2011-06-28 17:59:14 -0700 | [diff] [blame] | 739 | // Hide Edit/Delete buttons if in full screen mode on a phone |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 740 | if (!mIsDialog && !mIsTabletConfig || mWindowStyle == EventInfoFragment.FULL_WINDOW_STYLE) { |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 741 | mView.findViewById(R.id.event_info_buttons_container).setVisibility(View.GONE); |
| 742 | } |
| 743 | |
Sara Ting | cb5f568 | 2012-04-04 22:52:20 -0700 | [diff] [blame] | 744 | // Create a listener for the email guests button |
| 745 | View emailAttendeesButton = mView.findViewById(R.id.email_attendees_button); |
| 746 | if (emailAttendeesButton != null) { |
| 747 | emailAttendeesButton.setOnClickListener(new View.OnClickListener() { |
| 748 | @Override |
| 749 | public void onClick(View v) { |
| 750 | emailAttendees(); |
| 751 | } |
| 752 | }); |
| 753 | } |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 754 | |
Sara Ting | cb5f568 | 2012-04-04 22:52:20 -0700 | [diff] [blame] | 755 | // Create a listener for the add reminder button |
Michael Chan | b20942b | 2011-09-08 00:52:18 -0700 | [diff] [blame] | 756 | View reminderAddButton = mView.findViewById(R.id.reminder_add); |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 757 | View.OnClickListener addReminderOnClickListener = new View.OnClickListener() { |
| 758 | @Override |
| 759 | public void onClick(View v) { |
| 760 | addReminder(); |
RoboErik | 8b5743c | 2011-09-27 16:07:09 -0700 | [diff] [blame] | 761 | mUserModifiedReminders = true; |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 762 | } |
| 763 | }; |
| 764 | reminderAddButton.setOnClickListener(addReminderOnClickListener); |
| 765 | |
| 766 | // Set reminders variables |
| 767 | |
| 768 | SharedPreferences prefs = GeneralPreferences.getSharedPreferences(mActivity); |
| 769 | String defaultReminderString = prefs.getString( |
| 770 | GeneralPreferences.KEY_DEFAULT_REMINDER, GeneralPreferences.NO_REMINDER_STRING); |
| 771 | mDefaultReminderMinutes = Integer.parseInt(defaultReminderString); |
| 772 | prepareReminders(); |
| 773 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 774 | return mView; |
| 775 | } |
| 776 | |
Isaac Katzenelson | ac4350b | 2012-04-18 15:33:26 -0700 | [diff] [blame] | 777 | private final Runnable onDeleteRunnable = new Runnable() { |
Erik | 89ad082 | 2011-01-18 15:55:17 -0800 | [diff] [blame] | 778 | @Override |
| 779 | public void run() { |
RoboErik | 7c6236d | 2011-02-24 16:41:18 -0800 | [diff] [blame] | 780 | if (EventInfoFragment.this.mIsPaused) { |
| 781 | mDismissOnResume = true; |
| 782 | return; |
| 783 | } |
Erik | 89ad082 | 2011-01-18 15:55:17 -0800 | [diff] [blame] | 784 | if (EventInfoFragment.this.isVisible()) { |
| 785 | EventInfoFragment.this.dismiss(); |
| 786 | } |
| 787 | } |
| 788 | }; |
| 789 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 790 | private void updateTitle() { |
| 791 | Resources res = getActivity().getResources(); |
| 792 | if (mCanModifyCalendar && !mIsOrganizer) { |
| 793 | getActivity().setTitle(res.getString(R.string.event_info_title_invite)); |
| 794 | } else { |
| 795 | getActivity().setTitle(res.getString(R.string.event_info_title)); |
| 796 | } |
| 797 | } |
| 798 | |
| 799 | /** |
| 800 | * Initializes the event cursor, which is expected to point to the first |
| 801 | * (and only) result from a query. |
| 802 | * @return true if the cursor is empty. |
| 803 | */ |
| 804 | private boolean initEventCursor() { |
| 805 | if ((mEventCursor == null) || (mEventCursor.getCount() == 0)) { |
| 806 | return true; |
| 807 | } |
| 808 | mEventCursor.moveToFirst(); |
| 809 | mEventId = mEventCursor.getInt(EVENT_INDEX_ID); |
| 810 | String rRule = mEventCursor.getString(EVENT_INDEX_RRULE); |
Michael Chan | 66b2067 | 2010-12-20 13:50:28 -0800 | [diff] [blame] | 811 | mIsRepeating = !TextUtils.isEmpty(rRule); |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 812 | mHasAlarm = (mEventCursor.getInt(EVENT_INDEX_HAS_ALARM) == 1)?true:false; |
| 813 | mMaxReminders = mEventCursor.getInt(EVENT_INDEX_MAX_REMINDERS); |
| 814 | mCalendarAllowedReminders = mEventCursor.getString(EVENT_INDEX_ALLOWED_REMINDERS); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 815 | return false; |
| 816 | } |
| 817 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 818 | @SuppressWarnings("fallthrough") |
| 819 | private void initAttendeesCursor(View view) { |
Isaac Katzenelson | 6bcafcf | 2012-05-02 18:25:36 -0700 | [diff] [blame] | 820 | mOriginalAttendeeResponse = Attendees.ATTENDEE_STATUS_NONE; |
Erik | d845fbe | 2010-08-12 11:20:01 -0700 | [diff] [blame] | 821 | mCalendarOwnerAttendeeId = EditEventHelper.ATTENDEE_ID_NONE; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 822 | mNumOfAttendees = 0; |
| 823 | if (mAttendeesCursor != null) { |
| 824 | mNumOfAttendees = mAttendeesCursor.getCount(); |
| 825 | if (mAttendeesCursor.moveToFirst()) { |
| 826 | mAcceptedAttendees.clear(); |
| 827 | mDeclinedAttendees.clear(); |
| 828 | mTentativeAttendees.clear(); |
| 829 | mNoResponseAttendees.clear(); |
| 830 | |
| 831 | do { |
| 832 | int status = mAttendeesCursor.getInt(ATTENDEES_INDEX_STATUS); |
| 833 | String name = mAttendeesCursor.getString(ATTENDEES_INDEX_NAME); |
| 834 | String email = mAttendeesCursor.getString(ATTENDEES_INDEX_EMAIL); |
| 835 | |
Michael Chan | 83efa2d | 2012-04-24 17:42:21 -0700 | [diff] [blame] | 836 | if (mAttendeesCursor.getInt(ATTENDEES_INDEX_RELATIONSHIP) == |
| 837 | Attendees.RELATIONSHIP_ORGANIZER) { |
| 838 | |
| 839 | // Overwrites the one from Event table if available |
| 840 | if (!TextUtils.isEmpty(name)) { |
| 841 | mEventOrganizerDisplayName = name; |
| 842 | if (!mIsOrganizer) { |
| 843 | setVisibilityCommon(view, R.id.organizer_container, View.VISIBLE); |
| 844 | setTextCommon(view, R.id.organizer, mEventOrganizerDisplayName); |
| 845 | } |
| 846 | } |
| 847 | } |
| 848 | |
Erik | d845fbe | 2010-08-12 11:20:01 -0700 | [diff] [blame] | 849 | if (mCalendarOwnerAttendeeId == EditEventHelper.ATTENDEE_ID_NONE && |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 850 | mCalendarOwnerAccount.equalsIgnoreCase(email)) { |
| 851 | mCalendarOwnerAttendeeId = mAttendeesCursor.getInt(ATTENDEES_INDEX_ID); |
| 852 | mOriginalAttendeeResponse = mAttendeesCursor.getInt(ATTENDEES_INDEX_STATUS); |
| 853 | } else { |
Sara Ting | ddbc002 | 2012-04-26 17:08:46 -0700 | [diff] [blame] | 854 | String identity = mAttendeesCursor.getString(ATTENDEES_INDEX_IDENTITY); |
| 855 | String idNamespace = mAttendeesCursor.getString( |
| 856 | ATTENDEES_INDEX_ID_NAMESPACE); |
| 857 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 858 | // Don't show your own status in the list because: |
| 859 | // 1) it doesn't make sense for event without other guests. |
| 860 | // 2) there's a spinner for that for events with guests. |
| 861 | switch(status) { |
| 862 | case Attendees.ATTENDEE_STATUS_ACCEPTED: |
Isaac Katzenelson | fe25c50 | 2011-06-02 13:31:59 -0700 | [diff] [blame] | 863 | mAcceptedAttendees.add(new Attendee(name, email, |
Sara Ting | ddbc002 | 2012-04-26 17:08:46 -0700 | [diff] [blame] | 864 | Attendees.ATTENDEE_STATUS_ACCEPTED, identity, |
| 865 | idNamespace)); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 866 | break; |
| 867 | case Attendees.ATTENDEE_STATUS_DECLINED: |
Isaac Katzenelson | fe25c50 | 2011-06-02 13:31:59 -0700 | [diff] [blame] | 868 | mDeclinedAttendees.add(new Attendee(name, email, |
Sara Ting | ddbc002 | 2012-04-26 17:08:46 -0700 | [diff] [blame] | 869 | Attendees.ATTENDEE_STATUS_DECLINED, identity, |
| 870 | idNamespace)); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 871 | break; |
Michael Chan | 8ce3b7d | 2010-09-01 15:41:01 -0700 | [diff] [blame] | 872 | case Attendees.ATTENDEE_STATUS_TENTATIVE: |
Isaac Katzenelson | fe25c50 | 2011-06-02 13:31:59 -0700 | [diff] [blame] | 873 | mTentativeAttendees.add(new Attendee(name, email, |
Sara Ting | ddbc002 | 2012-04-26 17:08:46 -0700 | [diff] [blame] | 874 | Attendees.ATTENDEE_STATUS_TENTATIVE, identity, |
| 875 | idNamespace)); |
Michael Chan | 8ce3b7d | 2010-09-01 15:41:01 -0700 | [diff] [blame] | 876 | break; |
| 877 | default: |
Isaac Katzenelson | fe25c50 | 2011-06-02 13:31:59 -0700 | [diff] [blame] | 878 | mNoResponseAttendees.add(new Attendee(name, email, |
Sara Ting | ddbc002 | 2012-04-26 17:08:46 -0700 | [diff] [blame] | 879 | Attendees.ATTENDEE_STATUS_NONE, identity, |
| 880 | idNamespace)); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 881 | } |
| 882 | } |
| 883 | } while (mAttendeesCursor.moveToNext()); |
| 884 | mAttendeesCursor.moveToFirst(); |
| 885 | |
| 886 | updateAttendees(view); |
| 887 | } |
| 888 | } |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 889 | } |
| 890 | |
| 891 | @Override |
Mason Tang | 4003d1c | 2010-08-17 13:50:45 -0700 | [diff] [blame] | 892 | public void onSaveInstanceState(Bundle outState) { |
| 893 | super.onSaveInstanceState(outState); |
| 894 | outState.putLong(BUNDLE_KEY_EVENT_ID, mEventId); |
| 895 | outState.putLong(BUNDLE_KEY_START_MILLIS, mStartMillis); |
| 896 | outState.putLong(BUNDLE_KEY_END_MILLIS, mEndMillis); |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 897 | outState.putBoolean(BUNDLE_KEY_IS_DIALOG, mIsDialog); |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 898 | outState.putInt(BUNDLE_KEY_WINDOW_STYLE, mWindowStyle); |
Isaac Katzenelson | b0a313a | 2011-10-24 11:41:56 -0700 | [diff] [blame] | 899 | outState.putBoolean(BUNDLE_KEY_DELETE_DIALOG_VISIBLE, mDeleteDialogVisible); |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 900 | outState.putInt(BUNDLE_KEY_ATTENDEE_RESPONSE, mAttendeeResponseFromIntent); |
| 901 | } |
| 902 | |
| 903 | |
| 904 | @Override |
| 905 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { |
| 906 | super.onCreateOptionsMenu(menu, inflater); |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 907 | // Show edit/delete buttons only in non-dialog configuration |
| 908 | if (!mIsDialog && !mIsTabletConfig || mWindowStyle == EventInfoFragment.FULL_WINDOW_STYLE) { |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 909 | inflater.inflate(R.menu.event_info_title_bar, menu); |
RoboErik | d8353fb | 2011-07-21 11:28:11 -0700 | [diff] [blame] | 910 | mMenu = menu; |
| 911 | updateMenu(); |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 912 | } |
Mason Tang | 4003d1c | 2010-08-17 13:50:45 -0700 | [diff] [blame] | 913 | } |
| 914 | |
RoboErik | d8353fb | 2011-07-21 11:28:11 -0700 | [diff] [blame] | 915 | @Override |
| 916 | public boolean onOptionsItemSelected(MenuItem item) { |
| 917 | |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 918 | // If we're a dialog we don't want to handle menu buttons |
| 919 | if (mIsDialog) { |
RoboErik | d8353fb | 2011-07-21 11:28:11 -0700 | [diff] [blame] | 920 | return false; |
| 921 | } |
| 922 | // Handles option menu selections: |
| 923 | // Home button - close event info activity and start the main calendar |
| 924 | // one |
| 925 | // Edit button - start the event edit activity and close the info |
| 926 | // activity |
| 927 | // Delete button - start a delete query that calls a runnable that close |
| 928 | // the info activity |
| 929 | |
| 930 | switch (item.getItemId()) { |
| 931 | case android.R.id.home: |
RoboErik | 15b4dcc | 2011-09-19 16:21:27 -0700 | [diff] [blame] | 932 | Utils.returnToCalendarHome(mContext); |
RoboErik | d8353fb | 2011-07-21 11:28:11 -0700 | [diff] [blame] | 933 | mActivity.finish(); |
| 934 | return true; |
| 935 | case R.id.info_action_edit: |
| 936 | Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId); |
| 937 | Intent intent = new Intent(Intent.ACTION_EDIT, uri); |
| 938 | intent.putExtra(EXTRA_EVENT_BEGIN_TIME, mStartMillis); |
| 939 | intent.putExtra(EXTRA_EVENT_END_TIME, mEndMillis); |
Michael Chan | 8b1119b | 2012-01-06 16:04:55 -0800 | [diff] [blame] | 940 | intent.putExtra(EXTRA_EVENT_ALL_DAY, mAllDay); |
RoboErik | d8353fb | 2011-07-21 11:28:11 -0700 | [diff] [blame] | 941 | intent.setClass(mActivity, EditEventActivity.class); |
| 942 | intent.putExtra(EVENT_EDIT_ON_LAUNCH, true); |
| 943 | startActivity(intent); |
| 944 | mActivity.finish(); |
| 945 | break; |
| 946 | case R.id.info_action_delete: |
Isaac Katzenelson | b0a313a | 2011-10-24 11:41:56 -0700 | [diff] [blame] | 947 | mDeleteHelper = |
RoboErik | d8353fb | 2011-07-21 11:28:11 -0700 | [diff] [blame] | 948 | new DeleteEventHelper(mActivity, mActivity, true /* exitWhenDone */); |
Isaac Katzenelson | b0a313a | 2011-10-24 11:41:56 -0700 | [diff] [blame] | 949 | mDeleteHelper.setDeleteNotificationListener(EventInfoFragment.this); |
| 950 | mDeleteHelper.setOnDismissListener(createDeleteOnDismissListener()); |
| 951 | mDeleteDialogVisible = true; |
| 952 | mDeleteHelper.delete(mStartMillis, mEndMillis, mEventId, -1, onDeleteRunnable); |
RoboErik | d8353fb | 2011-07-21 11:28:11 -0700 | [diff] [blame] | 953 | break; |
| 954 | default: |
| 955 | break; |
| 956 | } |
| 957 | return super.onOptionsItemSelected(item); |
| 958 | } |
Mason Tang | 4003d1c | 2010-08-17 13:50:45 -0700 | [diff] [blame] | 959 | |
| 960 | @Override |
| 961 | public void onDestroyView() { |
Isaac Katzenelson | ac4350b | 2012-04-18 15:33:26 -0700 | [diff] [blame] | 962 | |
Isaac Katzenelson | b33cdf4 | 2011-10-14 18:15:18 -0700 | [diff] [blame] | 963 | if (!mEventDeletionStarted) { |
Isaac Katzenelson | ac4350b | 2012-04-18 15:33:26 -0700 | [diff] [blame] | 964 | boolean responseSaved = saveResponse(); |
| 965 | if (saveReminders() || responseSaved) { |
Isaac Katzenelson | b33cdf4 | 2011-10-14 18:15:18 -0700 | [diff] [blame] | 966 | Toast.makeText(getActivity(), R.string.saving_event, Toast.LENGTH_SHORT).show(); |
| 967 | } |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 968 | } |
Mason Tang | 4003d1c | 2010-08-17 13:50:45 -0700 | [diff] [blame] | 969 | super.onDestroyView(); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 970 | } |
| 971 | |
| 972 | @Override |
| 973 | public void onDestroy() { |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 974 | if (mEventCursor != null) { |
| 975 | mEventCursor.close(); |
| 976 | } |
| 977 | if (mCalendarsCursor != null) { |
| 978 | mCalendarsCursor.close(); |
| 979 | } |
| 980 | if (mAttendeesCursor != null) { |
| 981 | mAttendeesCursor.close(); |
| 982 | } |
Michael Chan | 71d0883 | 2010-08-25 18:28:59 -0700 | [diff] [blame] | 983 | super.onDestroy(); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 984 | } |
| 985 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 986 | /** |
| 987 | * Asynchronously saves the response to an invitation if the user changed |
| 988 | * the response. Returns true if the database will be updated. |
| 989 | * |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 990 | * @return true if the database will be changed |
| 991 | */ |
| 992 | private boolean saveResponse() { |
| 993 | if (mAttendeesCursor == null || mEventCursor == null) { |
| 994 | return false; |
| 995 | } |
Michael Chan | f92f46b | 2010-10-27 18:59:05 -0700 | [diff] [blame] | 996 | |
| 997 | RadioGroup radioGroup = (RadioGroup) getView().findViewById(R.id.response_value); |
| 998 | int status = getResponseFromButtonId(radioGroup.getCheckedRadioButtonId()); |
| 999 | if (status == Attendees.ATTENDEE_STATUS_NONE) { |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1000 | return false; |
| 1001 | } |
| 1002 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1003 | // If the status has not changed, then don't update the database |
| 1004 | if (status == mOriginalAttendeeResponse) { |
| 1005 | return false; |
| 1006 | } |
| 1007 | |
| 1008 | // If we never got an owner attendee id we can't set the status |
Erik | d845fbe | 2010-08-12 11:20:01 -0700 | [diff] [blame] | 1009 | if (mCalendarOwnerAttendeeId == EditEventHelper.ATTENDEE_ID_NONE) { |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1010 | return false; |
| 1011 | } |
| 1012 | |
| 1013 | if (!mIsRepeating) { |
| 1014 | // This is a non-repeating event |
| 1015 | updateResponse(mEventId, mCalendarOwnerAttendeeId, status); |
| 1016 | return true; |
| 1017 | } |
| 1018 | |
| 1019 | // This is a repeating event |
| 1020 | int whichEvents = mEditResponseHelper.getWhichEvents(); |
| 1021 | switch (whichEvents) { |
| 1022 | case -1: |
| 1023 | return false; |
| 1024 | case UPDATE_SINGLE: |
Andy McFadden | c928e3d | 2011-06-13 09:53:20 -0700 | [diff] [blame] | 1025 | createExceptionResponse(mEventId, status); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1026 | return true; |
| 1027 | case UPDATE_ALL: |
| 1028 | updateResponse(mEventId, mCalendarOwnerAttendeeId, status); |
| 1029 | return true; |
| 1030 | default: |
| 1031 | Log.e(TAG, "Unexpected choice for updating invitation response"); |
| 1032 | break; |
| 1033 | } |
| 1034 | return false; |
| 1035 | } |
| 1036 | |
| 1037 | private void updateResponse(long eventId, long attendeeId, int status) { |
| 1038 | // Update the attendee status in the attendees table. the provider |
| 1039 | // takes care of updating the self attendance status. |
| 1040 | ContentValues values = new ContentValues(); |
| 1041 | |
| 1042 | if (!TextUtils.isEmpty(mCalendarOwnerAccount)) { |
| 1043 | values.put(Attendees.ATTENDEE_EMAIL, mCalendarOwnerAccount); |
| 1044 | } |
| 1045 | values.put(Attendees.ATTENDEE_STATUS, status); |
| 1046 | values.put(Attendees.EVENT_ID, eventId); |
| 1047 | |
| 1048 | Uri uri = ContentUris.withAppendedId(Attendees.CONTENT_URI, attendeeId); |
| 1049 | |
| 1050 | mHandler.startUpdate(mHandler.getNextToken(), null, uri, values, |
| 1051 | null, null, Utils.UNDO_DELAY); |
| 1052 | } |
| 1053 | |
Andy McFadden | c928e3d | 2011-06-13 09:53:20 -0700 | [diff] [blame] | 1054 | /** |
| 1055 | * Creates an exception to a recurring event. The only change we're making is to the |
| 1056 | * "self attendee status" value. The provider will take care of updating the corresponding |
| 1057 | * Attendees.attendeeStatus entry. |
| 1058 | * |
| 1059 | * @param eventId The recurring event. |
| 1060 | * @param status The new value for selfAttendeeStatus. |
| 1061 | */ |
| 1062 | private void createExceptionResponse(long eventId, int status) { |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1063 | ContentValues values = new ContentValues(); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1064 | values.put(Events.ORIGINAL_INSTANCE_TIME, mStartMillis); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1065 | values.put(Events.SELF_ATTENDEE_STATUS, status); |
Andy McFadden | c928e3d | 2011-06-13 09:53:20 -0700 | [diff] [blame] | 1066 | values.put(Events.STATUS, Events.STATUS_CONFIRMED); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1067 | |
Erik | 364309f | 2010-12-23 14:26:26 -0800 | [diff] [blame] | 1068 | ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); |
Andy McFadden | 79b2c8c | 2011-06-30 15:26:05 -0700 | [diff] [blame] | 1069 | Uri exceptionUri = Uri.withAppendedPath(Events.CONTENT_EXCEPTION_URI, |
Andy McFadden | c928e3d | 2011-06-13 09:53:20 -0700 | [diff] [blame] | 1070 | String.valueOf(eventId)); |
| 1071 | ops.add(ContentProviderOperation.newInsert(exceptionUri).withValues(values).build()); |
Erik | 364309f | 2010-12-23 14:26:26 -0800 | [diff] [blame] | 1072 | |
Andy McFadden | c928e3d | 2011-06-13 09:53:20 -0700 | [diff] [blame] | 1073 | mHandler.startBatch(mHandler.getNextToken(), null, CalendarContract.AUTHORITY, ops, |
| 1074 | Utils.UNDO_DELAY); |
| 1075 | } |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1076 | |
Michael Chan | f92f46b | 2010-10-27 18:59:05 -0700 | [diff] [blame] | 1077 | public static int getResponseFromButtonId(int buttonId) { |
| 1078 | int response; |
| 1079 | switch (buttonId) { |
| 1080 | case R.id.response_yes: |
| 1081 | response = Attendees.ATTENDEE_STATUS_ACCEPTED; |
| 1082 | break; |
| 1083 | case R.id.response_maybe: |
| 1084 | response = Attendees.ATTENDEE_STATUS_TENTATIVE; |
| 1085 | break; |
| 1086 | case R.id.response_no: |
| 1087 | response = Attendees.ATTENDEE_STATUS_DECLINED; |
| 1088 | break; |
| 1089 | default: |
| 1090 | response = Attendees.ATTENDEE_STATUS_NONE; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1091 | } |
Michael Chan | f92f46b | 2010-10-27 18:59:05 -0700 | [diff] [blame] | 1092 | return response; |
| 1093 | } |
| 1094 | |
| 1095 | public static int findButtonIdForResponse(int response) { |
| 1096 | int buttonId; |
| 1097 | switch (response) { |
| 1098 | case Attendees.ATTENDEE_STATUS_ACCEPTED: |
| 1099 | buttonId = R.id.response_yes; |
| 1100 | break; |
| 1101 | case Attendees.ATTENDEE_STATUS_TENTATIVE: |
| 1102 | buttonId = R.id.response_maybe; |
| 1103 | break; |
| 1104 | case Attendees.ATTENDEE_STATUS_DECLINED: |
| 1105 | buttonId = R.id.response_no; |
| 1106 | break; |
| 1107 | default: |
| 1108 | buttonId = -1; |
| 1109 | } |
| 1110 | return buttonId; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1111 | } |
| 1112 | |
| 1113 | private void doEdit() { |
Erik | c41b99b | 2010-11-24 10:27:13 -0800 | [diff] [blame] | 1114 | Context c = getActivity(); |
| 1115 | // This ensures that we aren't in the process of closing and have been |
| 1116 | // unattached already |
| 1117 | if (c != null) { |
| 1118 | CalendarController.getInstance(c).sendEventRelatedEvent( |
Michael Chan | 61bf593 | 2011-08-11 12:57:58 -0700 | [diff] [blame] | 1119 | this, EventType.EDIT_EVENT, mEventId, mStartMillis, mEndMillis, 0 |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 1120 | , 0, -1); |
Erik | c41b99b | 2010-11-24 10:27:13 -0800 | [diff] [blame] | 1121 | } |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1122 | } |
| 1123 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1124 | private void updateEvent(View view) { |
Isaac Katzenelson | b7762cf | 2011-06-09 14:04:42 -0700 | [diff] [blame] | 1125 | if (mEventCursor == null || view == null) { |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1126 | return; |
| 1127 | } |
| 1128 | |
| 1129 | String eventName = mEventCursor.getString(EVENT_INDEX_TITLE); |
| 1130 | if (eventName == null || eventName.length() == 0) { |
| 1131 | eventName = getActivity().getString(R.string.no_title_label); |
| 1132 | } |
| 1133 | |
Michael Chan | 8b1119b | 2012-01-06 16:04:55 -0800 | [diff] [blame] | 1134 | mAllDay = mEventCursor.getInt(EVENT_INDEX_ALL_DAY) != 0; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1135 | String location = mEventCursor.getString(EVENT_INDEX_EVENT_LOCATION); |
| 1136 | String description = mEventCursor.getString(EVENT_INDEX_DESCRIPTION); |
| 1137 | String rRule = mEventCursor.getString(EVENT_INDEX_RRULE); |
Isaac Katzenelson | f6f7977 | 2011-06-02 16:29:18 -0700 | [diff] [blame] | 1138 | String eventTimezone = mEventCursor.getString(EVENT_INDEX_EVENT_TIMEZONE); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1139 | |
RoboErik | 4acb2fd | 2011-07-18 15:39:49 -0700 | [diff] [blame] | 1140 | mColor = Utils.getDisplayColorFromColor(mEventCursor.getInt(EVENT_INDEX_COLOR)); |
Isaac Katzenelson | fae6d5c | 2011-06-16 15:43:41 -0700 | [diff] [blame] | 1141 | mHeadlines.setBackgroundColor(mColor); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1142 | |
Sara Ting | 4e92627 | 2012-04-19 10:41:56 -0700 | [diff] [blame] | 1143 | // What |
| 1144 | if (eventName != null) { |
| 1145 | setTextCommon(view, R.id.title, eventName); |
| 1146 | } |
| 1147 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1148 | // When |
Isaac Katzenelson | fae6d5c | 2011-06-16 15:43:41 -0700 | [diff] [blame] | 1149 | // Set the date and repeats (if any) |
Sara Ting | 75f5366 | 2012-04-09 15:37:10 -0700 | [diff] [blame] | 1150 | String localTimezone = Utils.getTimeZone(mActivity, mTZUpdater); |
| 1151 | Activity context = getActivity(); |
Sara Ting | 23acd26 | 2012-04-20 13:27:39 -0700 | [diff] [blame] | 1152 | Resources resources = context.getResources(); |
| 1153 | String displayedDatetime = Utils.getDisplayedDatetime(mStartMillis, mEndMillis, |
| 1154 | System.currentTimeMillis(), localTimezone, mAllDay, context); |
| 1155 | String displayedTimezone = Utils.getDisplayedTimezone(mStartMillis, localTimezone, |
| 1156 | eventTimezone); |
| 1157 | int timezoneIndex = displayedDatetime.length(); |
| 1158 | if (displayedTimezone != null) { |
| 1159 | displayedDatetime += " " + displayedTimezone; |
| 1160 | } |
| 1161 | // Display the datetime. Make the timezone (if any) transparent. |
| 1162 | if (displayedTimezone == null) { |
| 1163 | setTextCommon(view, R.id.when_datetime, displayedDatetime); |
| 1164 | } else { |
| 1165 | SpannableStringBuilder sb = new SpannableStringBuilder(displayedDatetime); |
| 1166 | ForegroundColorSpan transparentColorSpan = new ForegroundColorSpan( |
| 1167 | resources.getColor(R.color.event_info_headline_transparent_color)); |
| 1168 | sb.setSpan(transparentColorSpan, timezoneIndex, displayedDatetime.length(), |
| 1169 | Spannable.SPAN_INCLUSIVE_INCLUSIVE); |
| 1170 | setTextCommon(view, R.id.when_datetime, sb); |
| 1171 | } |
Isaac Katzenelson | 74c9032 | 2011-06-02 15:20:29 -0700 | [diff] [blame] | 1172 | |
Sara Ting | 75f5366 | 2012-04-09 15:37:10 -0700 | [diff] [blame] | 1173 | // Display the repeat string (if any) |
Isaac Katzenelson | fae6d5c | 2011-06-16 15:43:41 -0700 | [diff] [blame] | 1174 | String repeatString = null; |
Michael Chan | bfa0e3f | 2010-12-20 12:36:55 -0800 | [diff] [blame] | 1175 | if (!TextUtils.isEmpty(rRule)) { |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1176 | EventRecurrence eventRecurrence = new EventRecurrence(); |
| 1177 | eventRecurrence.parse(rRule); |
Sara Ting | 75f5366 | 2012-04-09 15:37:10 -0700 | [diff] [blame] | 1178 | Time date = new Time(localTimezone); |
| 1179 | date.set(mStartMillis); |
Michael Chan | 8b1119b | 2012-01-06 16:04:55 -0800 | [diff] [blame] | 1180 | if (mAllDay) { |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1181 | date.timezone = Time.TIMEZONE_UTC; |
| 1182 | } |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1183 | eventRecurrence.setStartDate(date); |
Sara Ting | 23acd26 | 2012-04-20 13:27:39 -0700 | [diff] [blame] | 1184 | repeatString = EventRecurrenceFormatter.getRepeatString(resources, eventRecurrence); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1185 | } |
Sara Ting | 75f5366 | 2012-04-09 15:37:10 -0700 | [diff] [blame] | 1186 | if (repeatString == null) { |
| 1187 | view.findViewById(R.id.when_repeat).setVisibility(View.GONE); |
Isaac Katzenelson | fae6d5c | 2011-06-16 15:43:41 -0700 | [diff] [blame] | 1188 | } else { |
Sara Ting | 75f5366 | 2012-04-09 15:37:10 -0700 | [diff] [blame] | 1189 | setTextCommon(view, R.id.when_repeat, repeatString); |
Isaac Katzenelson | fae6d5c | 2011-06-16 15:43:41 -0700 | [diff] [blame] | 1190 | } |
| 1191 | |
Isaac Katzenelson | fae6d5c | 2011-06-16 15:43:41 -0700 | [diff] [blame] | 1192 | // Organizer view is setup in the updateCalendar method |
| 1193 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1194 | |
| 1195 | // Where |
Michael Chan | ddfb59d | 2011-01-12 15:41:21 -0800 | [diff] [blame] | 1196 | if (location == null || location.trim().length() == 0) { |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1197 | setVisibilityCommon(view, R.id.where, View.GONE); |
| 1198 | } else { |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 1199 | final TextView textView = mWhere; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1200 | if (textView != null) { |
Michael Chan | ddfb59d | 2011-01-12 15:41:21 -0800 | [diff] [blame] | 1201 | textView.setAutoLinkMask(0); |
| 1202 | textView.setText(location.trim()); |
Andy McFadden | af577fd | 2011-11-07 11:08:14 -0800 | [diff] [blame] | 1203 | try { |
| 1204 | linkifyTextView(textView); |
| 1205 | } catch (Exception ex) { |
| 1206 | // unexpected |
| 1207 | Log.e(TAG, "Linkification failed", ex); |
| 1208 | } |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 1209 | |
Michael Chan | ddfb59d | 2011-01-12 15:41:21 -0800 | [diff] [blame] | 1210 | textView.setOnTouchListener(new OnTouchListener() { |
Andy McFadden | c928e3d | 2011-06-13 09:53:20 -0700 | [diff] [blame] | 1211 | @Override |
Michael Chan | ddfb59d | 2011-01-12 15:41:21 -0800 | [diff] [blame] | 1212 | public boolean onTouch(View v, MotionEvent event) { |
| 1213 | try { |
| 1214 | return v.onTouchEvent(event); |
| 1215 | } catch (ActivityNotFoundException e) { |
| 1216 | // ignore |
| 1217 | return true; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1218 | } |
Michael Chan | ddfb59d | 2011-01-12 15:41:21 -0800 | [diff] [blame] | 1219 | } |
| 1220 | }); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1221 | } |
| 1222 | } |
| 1223 | |
| 1224 | // Description |
Michael Chan | 352e1a2 | 2010-09-28 05:15:08 -0700 | [diff] [blame] | 1225 | if (description != null && description.length() != 0) { |
Michael Chan | 99704a2 | 2011-11-11 10:24:37 -0800 | [diff] [blame] | 1226 | mDesc.setText(description); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1227 | } |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1228 | |
Michael Chan | 2c8485c | 2012-05-09 10:23:45 -0700 | [diff] [blame^] | 1229 | // Launch Custom App |
| 1230 | updateCustomAppButton(); |
| 1231 | } |
| 1232 | |
| 1233 | private void updateCustomAppButton() { |
| 1234 | buttonSetup: { |
| 1235 | final Button launchButton = (Button) mView.findViewById(R.id.launch_custom_app_button); |
| 1236 | if (launchButton == null) |
| 1237 | break buttonSetup; |
| 1238 | |
| 1239 | final String customAppPackage = mEventCursor.getString(EVENT_INDEX_CUSTOM_APP_PACKAGE); |
| 1240 | final String customAppUri = mEventCursor.getString(EVENT_INDEX_CUSTOM_APP_URI); |
| 1241 | |
| 1242 | if (TextUtils.isEmpty(customAppPackage) || TextUtils.isEmpty(customAppUri)) |
| 1243 | break buttonSetup; |
| 1244 | |
| 1245 | PackageManager pm = mContext.getPackageManager(); |
| 1246 | if (pm == null) |
| 1247 | break buttonSetup; |
| 1248 | |
| 1249 | ApplicationInfo info; |
| 1250 | try { |
| 1251 | info = pm.getApplicationInfo(customAppPackage, 0); |
| 1252 | if (info == null) |
| 1253 | break buttonSetup; |
| 1254 | } catch (NameNotFoundException e) { |
| 1255 | break buttonSetup; |
| 1256 | } |
| 1257 | |
| 1258 | Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId); |
| 1259 | final Intent intent = new Intent(CalendarContract.ACTION_HANDLE_CUSTOM_EVENT, uri); |
| 1260 | intent.setPackage(customAppPackage); |
| 1261 | intent.putExtra(CalendarContract.EXTRA_CUSTOM_APP_URI, customAppUri); |
| 1262 | intent.putExtra(EXTRA_EVENT_BEGIN_TIME, mStartMillis); |
| 1263 | |
| 1264 | // See if we have a taker for our intent |
| 1265 | if (pm.resolveActivity(intent, 0) == null) |
| 1266 | break buttonSetup; |
| 1267 | |
| 1268 | Drawable icon = pm.getApplicationIcon(info); |
| 1269 | if (icon != null) { |
| 1270 | |
| 1271 | Drawable[] d = launchButton.getCompoundDrawables(); |
| 1272 | icon.setBounds(0, 0, mCustomAppIconSize, mCustomAppIconSize); |
| 1273 | launchButton.setCompoundDrawables(icon, d[1], d[2], d[3]); |
| 1274 | } |
| 1275 | |
| 1276 | CharSequence label = pm.getApplicationLabel(info); |
| 1277 | if (label != null && label.length() != 0) { |
| 1278 | launchButton.setText(label); |
| 1279 | } else if (icon == null) { |
| 1280 | // No icon && no label. Hide button? |
| 1281 | break buttonSetup; |
| 1282 | } |
| 1283 | |
| 1284 | // Launch custom app |
| 1285 | launchButton.setOnClickListener(new View.OnClickListener() { |
| 1286 | @Override |
| 1287 | public void onClick(View v) { |
| 1288 | try { |
| 1289 | startActivityForResult(intent, 0); |
| 1290 | } catch (ActivityNotFoundException e) { |
| 1291 | // Shouldn't happen as we checked it already |
| 1292 | setVisibilityCommon(mView, R.id.launch_custom_app_container, View.GONE); |
| 1293 | } |
| 1294 | } |
| 1295 | }); |
| 1296 | |
| 1297 | setVisibilityCommon(mView, R.id.launch_custom_app_container, View.VISIBLE); |
| 1298 | return; |
| 1299 | |
| 1300 | } |
| 1301 | |
| 1302 | setVisibilityCommon(mView, R.id.launch_custom_app_container, View.GONE); |
| 1303 | return; |
Isaac Katzenelson | 8f4d969 | 2012-02-23 17:34:07 -0800 | [diff] [blame] | 1304 | } |
Sara Ting | 75f5366 | 2012-04-09 15:37:10 -0700 | [diff] [blame] | 1305 | |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 1306 | /** |
Andy McFadden | fd8ce5e | 2011-11-15 15:44:57 -0800 | [diff] [blame] | 1307 | * Finds North American Numbering Plan (NANP) phone numbers in the input text. |
| 1308 | * |
| 1309 | * @param text The text to scan. |
| 1310 | * @return A list of [start, end) pairs indicating the positions of phone numbers in the input. |
| 1311 | */ |
| 1312 | // @VisibleForTesting |
| 1313 | static int[] findNanpPhoneNumbers(CharSequence text) { |
| 1314 | ArrayList<Integer> list = new ArrayList<Integer>(); |
| 1315 | |
| 1316 | int startPos = 0; |
| 1317 | int endPos = text.length() - NANP_MIN_DIGITS + 1; |
| 1318 | if (endPos < 0) { |
| 1319 | return new int[] {}; |
| 1320 | } |
| 1321 | |
| 1322 | /* |
| 1323 | * We can't just strip the whitespace out and crunch it down, because the whitespace |
| 1324 | * is significant. March through, trying to figure out where numbers start and end. |
| 1325 | */ |
| 1326 | while (startPos < endPos) { |
| 1327 | // skip whitespace |
| 1328 | while (Character.isWhitespace(text.charAt(startPos)) && startPos < endPos) { |
| 1329 | startPos++; |
| 1330 | } |
| 1331 | if (startPos == endPos) { |
| 1332 | break; |
| 1333 | } |
| 1334 | |
| 1335 | // check for a match at this position |
| 1336 | int matchEnd = findNanpMatchEnd(text, startPos); |
| 1337 | if (matchEnd > startPos) { |
| 1338 | list.add(startPos); |
| 1339 | list.add(matchEnd); |
| 1340 | startPos = matchEnd; // skip past match |
| 1341 | } else { |
| 1342 | // skip to next whitespace char |
| 1343 | while (!Character.isWhitespace(text.charAt(startPos)) && startPos < endPos) { |
| 1344 | startPos++; |
| 1345 | } |
| 1346 | } |
| 1347 | } |
| 1348 | |
| 1349 | int[] result = new int[list.size()]; |
| 1350 | for (int i = list.size() - 1; i >= 0; i--) { |
| 1351 | result[i] = list.get(i); |
| 1352 | } |
| 1353 | return result; |
| 1354 | } |
| 1355 | |
| 1356 | /** |
| 1357 | * Checks to see if there is a valid phone number in the input, starting at the specified |
| 1358 | * offset. If so, the index of the last character + 1 is returned. The input is assumed |
| 1359 | * to begin with a non-whitespace character. |
| 1360 | * |
| 1361 | * @return Exclusive end position, or -1 if not a match. |
| 1362 | */ |
| 1363 | private static int findNanpMatchEnd(CharSequence text, int startPos) { |
| 1364 | /* |
| 1365 | * A few interesting cases: |
| 1366 | * 94043 # too short, ignore |
| 1367 | * 123456789012 # too long, ignore |
| 1368 | * +1 (650) 555-1212 # 11 digits, spaces |
| 1369 | * (650) 555-1212, (650) 555-1213 # two numbers, return first |
| 1370 | * 1-650-555-1212 # 11 digits with leading '1' |
| 1371 | * *#650.555.1212#*! # 10 digits, include #*, ignore trailing '!' |
| 1372 | * 555.1212 # 7 digits |
| 1373 | * |
| 1374 | * For the most part we want to break on whitespace, but it's common to leave a space |
| 1375 | * between the initial '1' and/or after the area code. |
| 1376 | */ |
| 1377 | |
| 1378 | int endPos = text.length(); |
| 1379 | int curPos = startPos; |
| 1380 | int foundDigits = 0; |
| 1381 | char firstDigit = 'x'; |
| 1382 | |
| 1383 | while (curPos <= endPos) { |
| 1384 | char ch; |
| 1385 | if (curPos < endPos) { |
| 1386 | ch = text.charAt(curPos); |
| 1387 | } else { |
| 1388 | ch = 27; // fake invalid symbol at end to trigger loop break |
| 1389 | } |
| 1390 | |
| 1391 | if (Character.isDigit(ch)) { |
| 1392 | if (foundDigits == 0) { |
| 1393 | firstDigit = ch; |
| 1394 | } |
| 1395 | foundDigits++; |
| 1396 | if (foundDigits > NANP_MAX_DIGITS) { |
| 1397 | // too many digits, stop early |
| 1398 | return -1; |
| 1399 | } |
| 1400 | } else if (Character.isWhitespace(ch)) { |
| 1401 | if (!( (firstDigit == '1' && (foundDigits == 1 || foundDigits == 4)) || |
| 1402 | (foundDigits == 3)) ) { |
| 1403 | break; |
| 1404 | } |
| 1405 | } else if (NANP_ALLOWED_SYMBOLS.indexOf(ch) == -1) { |
| 1406 | break; |
| 1407 | } |
| 1408 | // else it's an allowed symbol |
| 1409 | |
| 1410 | curPos++; |
| 1411 | } |
| 1412 | |
| 1413 | if ((firstDigit != '1' && (foundDigits == 7 || foundDigits == 10)) || |
| 1414 | (firstDigit == '1' && foundDigits == 11)) { |
| 1415 | // match |
| 1416 | return curPos; |
| 1417 | } |
| 1418 | |
| 1419 | return -1; |
| 1420 | } |
| 1421 | |
| 1422 | /** |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 1423 | * Replaces stretches of text that look like addresses and phone numbers with clickable |
| 1424 | * links. |
| 1425 | * <p> |
| 1426 | * This is really just an enhanced version of Linkify.addLinks(). |
| 1427 | */ |
| 1428 | private static void linkifyTextView(TextView textView) { |
| 1429 | /* |
| 1430 | * If the text includes a street address like "1600 Amphitheater Parkway, 94043", |
| 1431 | * the current Linkify code will identify "94043" as a phone number and invite |
| 1432 | * you to dial it (and not provide a map link for the address). We want to |
| 1433 | * have better recognition of phone numbers without losing any of the existing |
| 1434 | * annotations. |
| 1435 | * |
| 1436 | * Ideally this would be addressed by improving Linkify. For now we manage it as |
| 1437 | * a second pass over the text. |
| 1438 | * |
| 1439 | * URIs and e-mail addresses are pretty easy to pick out of text. Phone numbers |
| 1440 | * are a bit tricky because they have radically different formats in different |
| 1441 | * countries, in terms of both the digits and the way in which they are commonly |
| 1442 | * written or presented (e.g. the punctuation and spaces in "(650) 555-1212"). |
| 1443 | * The expected format of a street address is defined in WebView.findAddress(). It's |
| 1444 | * pretty narrowly defined, so it won't often match. |
| 1445 | * |
| 1446 | * The RFC 3966 specification defines the format of a "tel:" URI. |
| 1447 | */ |
| 1448 | |
| 1449 | /* |
Andy McFadden | fd8ce5e | 2011-11-15 15:44:57 -0800 | [diff] [blame] | 1450 | * If we're in the US, handle this specially. Otherwise, punt to Linkify. |
| 1451 | */ |
| 1452 | String defaultPhoneRegion = System.getProperty("user.region", "US"); |
| 1453 | if (!defaultPhoneRegion.equals("US")) { |
| 1454 | Linkify.addLinks(textView, Linkify.ALL); |
| 1455 | return; |
| 1456 | } |
| 1457 | |
| 1458 | /* |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 1459 | * Start by letting Linkify find anything that isn't a phone number. We have to let it |
| 1460 | * run first because every invocation removes all previous URLSpan annotations. |
Andy McFadden | fd8ce5e | 2011-11-15 15:44:57 -0800 | [diff] [blame] | 1461 | * |
| 1462 | * Ideally we'd use the external/libphonenumber routines, but those aren't available |
| 1463 | * to unbundled applications. |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 1464 | */ |
| 1465 | boolean linkifyFoundLinks = Linkify.addLinks(textView, |
| 1466 | Linkify.ALL & ~(Linkify.PHONE_NUMBERS)); |
| 1467 | |
| 1468 | /* |
| 1469 | * Search for phone numbers. |
| 1470 | * |
Andy McFadden | fd8ce5e | 2011-11-15 15:44:57 -0800 | [diff] [blame] | 1471 | * Some URIs contain strings of digits that look like phone numbers. If both the URI |
| 1472 | * scanner and the phone number scanner find them, we want the URI link to win. Since |
| 1473 | * the URI scanner runs first, we just need to avoid creating overlapping spans. |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 1474 | */ |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 1475 | CharSequence text = textView.getText(); |
Andy McFadden | fd8ce5e | 2011-11-15 15:44:57 -0800 | [diff] [blame] | 1476 | int[] phoneSequences = findNanpPhoneNumbers(text); |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 1477 | |
| 1478 | /* |
| 1479 | * If the contents of the TextView are already Spannable (which will be the case if |
| 1480 | * Linkify found stuff, but might not be otherwise), we can just add annotations |
| 1481 | * to what's there. If it's not, and we find phone numbers, we need to convert it to |
| 1482 | * a Spannable form. (This mimics the behavior of Linkable.addLinks().) |
| 1483 | */ |
| 1484 | Spannable spanText; |
| 1485 | if (text instanceof SpannableString) { |
| 1486 | spanText = (SpannableString) text; |
| 1487 | } else { |
| 1488 | spanText = SpannableString.valueOf(text); |
| 1489 | } |
| 1490 | |
| 1491 | /* |
| 1492 | * Get a list of any spans created by Linkify, for the overlapping span check. |
| 1493 | */ |
| 1494 | URLSpan[] existingSpans = spanText.getSpans(0, spanText.length(), URLSpan.class); |
| 1495 | |
| 1496 | /* |
| 1497 | * Insert spans for the numbers we found. We generate "tel:" URIs. |
| 1498 | */ |
| 1499 | int phoneCount = 0; |
Andy McFadden | fd8ce5e | 2011-11-15 15:44:57 -0800 | [diff] [blame] | 1500 | for (int match = 0; match < phoneSequences.length / 2; match++) { |
| 1501 | int start = phoneSequences[match*2]; |
| 1502 | int end = phoneSequences[match*2 + 1]; |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 1503 | |
| 1504 | if (spanWillOverlap(spanText, existingSpans, start, end)) { |
| 1505 | if (Log.isLoggable(TAG, Log.VERBOSE)) { |
Andy McFadden | fd8ce5e | 2011-11-15 15:44:57 -0800 | [diff] [blame] | 1506 | CharSequence seq = text.subSequence(start, end); |
| 1507 | Log.v(TAG, "Not linkifying " + seq + " as phone number due to overlap"); |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 1508 | } |
| 1509 | continue; |
| 1510 | } |
| 1511 | |
| 1512 | /* |
Andy McFadden | 73b0765 | 2011-08-23 15:45:09 -0700 | [diff] [blame] | 1513 | * The Linkify code takes the matching span and strips out everything that isn't a |
| 1514 | * digit or '+' sign. We do the same here. Extension numbers will get appended |
| 1515 | * without a separator, but the dialer wasn't doing anything useful with ";ext=" |
| 1516 | * anyway. |
| 1517 | */ |
| 1518 | |
| 1519 | //String dialStr = phoneUtil.format(match.number(), |
| 1520 | // PhoneNumberUtil.PhoneNumberFormat.RFC3966); |
| 1521 | StringBuilder dialBuilder = new StringBuilder(); |
| 1522 | for (int i = start; i < end; i++) { |
| 1523 | char ch = spanText.charAt(i); |
| 1524 | if (ch == '+' || Character.isDigit(ch)) { |
| 1525 | dialBuilder.append(ch); |
| 1526 | } |
| 1527 | } |
| 1528 | URLSpan span = new URLSpan("tel:" + dialBuilder.toString()); |
| 1529 | |
| 1530 | spanText.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); |
| 1531 | phoneCount++; |
| 1532 | } |
| 1533 | |
| 1534 | if (phoneCount != 0) { |
| 1535 | // If we had to "upgrade" to Spannable, store the object into the TextView. |
| 1536 | if (spanText != text) { |
| 1537 | textView.setText(spanText); |
| 1538 | } |
| 1539 | |
| 1540 | // Linkify.addLinks() sets the TextView movement method if it finds any links. We |
| 1541 | // want to do the same here. (This is cloned from Linkify.addLinkMovementMethod().) |
| 1542 | MovementMethod mm = textView.getMovementMethod(); |
| 1543 | |
| 1544 | if ((mm == null) || !(mm instanceof LinkMovementMethod)) { |
| 1545 | if (textView.getLinksClickable()) { |
| 1546 | textView.setMovementMethod(LinkMovementMethod.getInstance()); |
| 1547 | } |
| 1548 | } |
| 1549 | } |
| 1550 | |
| 1551 | if (!linkifyFoundLinks && phoneCount == 0) { |
| 1552 | if (Log.isLoggable(TAG, Log.VERBOSE)) { |
| 1553 | Log.v(TAG, "No linkification matches, using geo default"); |
| 1554 | } |
| 1555 | Linkify.addLinks(textView, mWildcardPattern, "geo:0,0?q="); |
| 1556 | } |
| 1557 | } |
| 1558 | |
| 1559 | /** |
| 1560 | * Determines whether a new span at [start,end) will overlap with any existing span. |
| 1561 | */ |
| 1562 | private static boolean spanWillOverlap(Spannable spanText, URLSpan[] spanList, int start, |
| 1563 | int end) { |
| 1564 | if (start == end) { |
| 1565 | // empty span, ignore |
| 1566 | return false; |
| 1567 | } |
| 1568 | for (URLSpan span : spanList) { |
| 1569 | int existingStart = spanText.getSpanStart(span); |
| 1570 | int existingEnd = spanText.getSpanEnd(span); |
| 1571 | if ((start >= existingStart && start < existingEnd) || |
| 1572 | end > existingStart && end <= existingEnd) { |
| 1573 | return true; |
| 1574 | } |
| 1575 | } |
| 1576 | |
| 1577 | return false; |
| 1578 | } |
| 1579 | |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 1580 | private void sendAccessibilityEvent() { |
Andy McFadden | ef31a98 | 2011-06-09 07:38:56 -0700 | [diff] [blame] | 1581 | AccessibilityManager am = |
| 1582 | (AccessibilityManager) getActivity().getSystemService(Service.ACCESSIBILITY_SERVICE); |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 1583 | if (!am.isEnabled()) { |
| 1584 | return; |
| 1585 | } |
| 1586 | |
| 1587 | AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_FOCUSED); |
| 1588 | event.setClassName(getClass().getName()); |
| 1589 | event.setPackageName(getActivity().getPackageName()); |
| 1590 | List<CharSequence> text = event.getText(); |
| 1591 | |
Michael Chan | 99704a2 | 2011-11-11 10:24:37 -0800 | [diff] [blame] | 1592 | addFieldToAccessibilityEvent(text, mTitle, null); |
Sara Ting | 75f5366 | 2012-04-09 15:37:10 -0700 | [diff] [blame] | 1593 | addFieldToAccessibilityEvent(text, mWhenDateTime, null); |
Michael Chan | 99704a2 | 2011-11-11 10:24:37 -0800 | [diff] [blame] | 1594 | addFieldToAccessibilityEvent(text, mWhere, null); |
| 1595 | addFieldToAccessibilityEvent(text, null, mDesc); |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 1596 | |
| 1597 | RadioGroup response = (RadioGroup) getView().findViewById(R.id.response_value); |
| 1598 | if (response.getVisibility() == View.VISIBLE) { |
| 1599 | int id = response.getCheckedRadioButtonId(); |
| 1600 | if (id != View.NO_ID) { |
| 1601 | text.add(((TextView) getView().findViewById(R.id.response_label)).getText()); |
| 1602 | text.add((((RadioButton) (response.findViewById(id))).getText() + PERIOD_SPACE)); |
| 1603 | } |
| 1604 | } |
| 1605 | |
| 1606 | am.sendAccessibilityEvent(event); |
| 1607 | } |
| 1608 | |
Michael Chan | 99704a2 | 2011-11-11 10:24:37 -0800 | [diff] [blame] | 1609 | private void addFieldToAccessibilityEvent(List<CharSequence> text, TextView tv, |
| 1610 | ExpandableTextView etv) { |
Michael Chan | 3389397 | 2011-11-16 12:45:53 -0800 | [diff] [blame] | 1611 | CharSequence cs; |
Michael Chan | 99704a2 | 2011-11-11 10:24:37 -0800 | [diff] [blame] | 1612 | if (tv != null) { |
Michael Chan | 3389397 | 2011-11-16 12:45:53 -0800 | [diff] [blame] | 1613 | cs = tv.getText(); |
Michael Chan | 99704a2 | 2011-11-11 10:24:37 -0800 | [diff] [blame] | 1614 | } else if (etv != null) { |
Michael Chan | 3389397 | 2011-11-16 12:45:53 -0800 | [diff] [blame] | 1615 | cs = etv.getText(); |
Michael Chan | 99704a2 | 2011-11-11 10:24:37 -0800 | [diff] [blame] | 1616 | } else { |
Isaac Katzenelson | 9ceed1f | 2011-06-08 17:26:26 -0700 | [diff] [blame] | 1617 | return; |
| 1618 | } |
Michael Chan | 99704a2 | 2011-11-11 10:24:37 -0800 | [diff] [blame] | 1619 | |
Michael Chan | 3389397 | 2011-11-16 12:45:53 -0800 | [diff] [blame] | 1620 | if (!TextUtils.isEmpty(cs)) { |
| 1621 | cs = cs.toString().trim(); |
| 1622 | if (cs.length() > 0) { |
| 1623 | text.add(cs); |
| 1624 | text.add(PERIOD_SPACE); |
| 1625 | } |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 1626 | } |
| 1627 | } |
| 1628 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1629 | private void updateCalendar(View view) { |
| 1630 | mCalendarOwnerAccount = ""; |
| 1631 | if (mCalendarsCursor != null && mEventCursor != null) { |
| 1632 | mCalendarsCursor.moveToFirst(); |
| 1633 | String tempAccount = mCalendarsCursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT); |
| 1634 | mCalendarOwnerAccount = (tempAccount == null) ? "" : tempAccount; |
Michael Chan | 352e1a2 | 2010-09-28 05:15:08 -0700 | [diff] [blame] | 1635 | mOwnerCanRespond = mCalendarsCursor.getInt(CALENDARS_INDEX_OWNER_CAN_RESPOND) != 0; |
Sara Ting | 42896f7 | 2012-03-15 15:24:36 -0700 | [diff] [blame] | 1636 | mSyncAccountName = mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_NAME); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1637 | |
| 1638 | String displayName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME); |
| 1639 | |
| 1640 | // start duplicate calendars query |
| 1641 | mHandler.startQuery(TOKEN_QUERY_DUPLICATE_CALENDARS, null, Calendars.CONTENT_URI, |
| 1642 | CALENDARS_PROJECTION, CALENDARS_DUPLICATE_NAME_WHERE, |
| 1643 | new String[] {displayName}, null); |
| 1644 | |
Michael Chan | 83efa2d | 2012-04-24 17:42:21 -0700 | [diff] [blame] | 1645 | mEventOrganizerEmail = mEventCursor.getString(EVENT_INDEX_ORGANIZER); |
| 1646 | mIsOrganizer = mCalendarOwnerAccount.equalsIgnoreCase(mEventOrganizerEmail); |
| 1647 | |
Sara Ting | 0c0da94 | 2012-04-27 10:35:05 -0700 | [diff] [blame] | 1648 | if (!TextUtils.isEmpty(mEventOrganizerEmail) && |
| 1649 | !mEventOrganizerEmail.endsWith(Utils.MACHINE_GENERATED_ADDRESS)) { |
Michael Chan | 83efa2d | 2012-04-24 17:42:21 -0700 | [diff] [blame] | 1650 | mEventOrganizerDisplayName = mEventOrganizerEmail; |
| 1651 | } |
| 1652 | |
| 1653 | if (!mIsOrganizer && !TextUtils.isEmpty(mEventOrganizerDisplayName)) { |
| 1654 | setTextCommon(view, R.id.organizer, mEventOrganizerDisplayName); |
Isaac Katzenelson | b7762cf | 2011-06-09 14:04:42 -0700 | [diff] [blame] | 1655 | setVisibilityCommon(view, R.id.organizer_container, View.VISIBLE); |
| 1656 | } else { |
| 1657 | setVisibilityCommon(view, R.id.organizer_container, View.GONE); |
| 1658 | } |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1659 | mHasAttendeeData = mEventCursor.getInt(EVENT_INDEX_HAS_ATTENDEE_DATA) != 0; |
RoboErik | 65eeb79 | 2011-08-08 12:54:00 -0700 | [diff] [blame] | 1660 | mCanModifyCalendar = mEventCursor.getInt(EVENT_INDEX_ACCESS_LEVEL) |
| 1661 | >= Calendars.CAL_ACCESS_CONTRIBUTOR; |
| 1662 | // TODO add "|| guestCanModify" after b/1299071 is fixed |
| 1663 | mCanModifyEvent = mCanModifyCalendar && mIsOrganizer; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1664 | mIsBusyFreeCalendar = |
RoboErik | ef2add9 | 2011-06-09 14:49:53 -0700 | [diff] [blame] | 1665 | mEventCursor.getInt(EVENT_INDEX_ACCESS_LEVEL) == Calendars.CAL_ACCESS_FREEBUSY; |
Michael Chan | 352e1a2 | 2010-09-28 05:15:08 -0700 | [diff] [blame] | 1666 | |
| 1667 | if (!mIsBusyFreeCalendar) { |
Michael Chan | 8ce3b7d | 2010-09-01 15:41:01 -0700 | [diff] [blame] | 1668 | Button b = (Button) mView.findViewById(R.id.edit); |
Michael Chan | 352e1a2 | 2010-09-28 05:15:08 -0700 | [diff] [blame] | 1669 | b.setEnabled(true); |
Michael Chan | 8ce3b7d | 2010-09-01 15:41:01 -0700 | [diff] [blame] | 1670 | b.setOnClickListener(new OnClickListener() { |
| 1671 | @Override |
| 1672 | public void onClick(View v) { |
| 1673 | doEdit(); |
Isaac Katzenelson | 10b6021 | 2011-06-28 17:59:14 -0700 | [diff] [blame] | 1674 | // For dialogs, just close the fragment |
| 1675 | // For full screen, close activity on phone, leave it for tablet |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 1676 | if (mIsDialog) { |
| 1677 | EventInfoFragment.this.dismiss(); |
| 1678 | } |
Isaac Katzenelson | 10b6021 | 2011-06-28 17:59:14 -0700 | [diff] [blame] | 1679 | else if (!mIsTabletConfig){ |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 1680 | getActivity().finish(); |
| 1681 | } |
Michael Chan | 352e1a2 | 2010-09-28 05:15:08 -0700 | [diff] [blame] | 1682 | } |
| 1683 | }); |
Michael Chan | 8ce3b7d | 2010-09-01 15:41:01 -0700 | [diff] [blame] | 1684 | } |
Mindy Pereira | dd15169 | 2011-08-29 14:05:26 -0700 | [diff] [blame] | 1685 | View button; |
Sara Ting | 42896f7 | 2012-03-15 15:24:36 -0700 | [diff] [blame] | 1686 | if (mCanModifyCalendar) { |
Mindy Pereira | dd15169 | 2011-08-29 14:05:26 -0700 | [diff] [blame] | 1687 | button = mView.findViewById(R.id.delete); |
| 1688 | if (button != null) { |
Sara Ting | 42896f7 | 2012-03-15 15:24:36 -0700 | [diff] [blame] | 1689 | button.setEnabled(true); |
| 1690 | button.setVisibility(View.VISIBLE); |
RoboErik | 65eeb79 | 2011-08-08 12:54:00 -0700 | [diff] [blame] | 1691 | } |
Mindy Pereira | dd15169 | 2011-08-29 14:05:26 -0700 | [diff] [blame] | 1692 | } |
Sara Ting | 42896f7 | 2012-03-15 15:24:36 -0700 | [diff] [blame] | 1693 | if (mCanModifyEvent) { |
Mindy Pereira | dd15169 | 2011-08-29 14:05:26 -0700 | [diff] [blame] | 1694 | button = mView.findViewById(R.id.edit); |
| 1695 | if (button != null) { |
Sara Ting | 42896f7 | 2012-03-15 15:24:36 -0700 | [diff] [blame] | 1696 | button.setEnabled(true); |
| 1697 | button.setVisibility(View.VISIBLE); |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 1698 | } |
RoboErik | d8353fb | 2011-07-21 11:28:11 -0700 | [diff] [blame] | 1699 | } |
Sara Ting | 42896f7 | 2012-03-15 15:24:36 -0700 | [diff] [blame] | 1700 | |
Isaac Katzenelson | 7ef2981 | 2011-10-25 18:00:50 -0700 | [diff] [blame] | 1701 | if ((!mIsDialog && !mIsTabletConfig || |
| 1702 | mWindowStyle == EventInfoFragment.FULL_WINDOW_STYLE) && mMenu != null) { |
RoboErik | d8353fb | 2011-07-21 11:28:11 -0700 | [diff] [blame] | 1703 | mActivity.invalidateOptionsMenu(); |
RoboErik | 69be855 | 2011-02-14 16:51:59 -0800 | [diff] [blame] | 1704 | } |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1705 | } else { |
Michael Chan | 71b221a | 2010-10-25 17:55:44 -0700 | [diff] [blame] | 1706 | setVisibilityCommon(view, R.id.calendar, View.GONE); |
Erik | 259b8f9 | 2011-01-12 14:01:12 -0800 | [diff] [blame] | 1707 | sendAccessibilityEventIfQueryDone(TOKEN_QUERY_DUPLICATE_CALENDARS); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1708 | } |
| 1709 | } |
| 1710 | |
RoboErik | d8353fb | 2011-07-21 11:28:11 -0700 | [diff] [blame] | 1711 | /** |
| 1712 | * |
| 1713 | */ |
| 1714 | private void updateMenu() { |
| 1715 | if (mMenu == null) { |
| 1716 | return; |
| 1717 | } |
| 1718 | MenuItem delete = mMenu.findItem(R.id.info_action_delete); |
| 1719 | MenuItem edit = mMenu.findItem(R.id.info_action_edit); |
| 1720 | if (delete != null) { |
| 1721 | delete.setVisible(mCanModifyCalendar); |
| 1722 | delete.setEnabled(mCanModifyCalendar); |
| 1723 | } |
| 1724 | if (edit != null) { |
RoboErik | 65eeb79 | 2011-08-08 12:54:00 -0700 | [diff] [blame] | 1725 | edit.setVisible(mCanModifyEvent); |
| 1726 | edit.setEnabled(mCanModifyEvent); |
RoboErik | d8353fb | 2011-07-21 11:28:11 -0700 | [diff] [blame] | 1727 | } |
| 1728 | } |
| 1729 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1730 | private void updateAttendees(View view) { |
Isaac Katzenelson | fae6d5c | 2011-06-16 15:43:41 -0700 | [diff] [blame] | 1731 | if (mAcceptedAttendees.size() + mDeclinedAttendees.size() + |
| 1732 | mTentativeAttendees.size() + mNoResponseAttendees.size() > 0) { |
RoboErik | c7f3c38 | 2011-08-31 14:43:24 -0700 | [diff] [blame] | 1733 | mLongAttendees.clearAttendees(); |
RoboErik | 4acb2fd | 2011-07-18 15:39:49 -0700 | [diff] [blame] | 1734 | (mLongAttendees).addAttendees(mAcceptedAttendees); |
| 1735 | (mLongAttendees).addAttendees(mDeclinedAttendees); |
| 1736 | (mLongAttendees).addAttendees(mTentativeAttendees); |
| 1737 | (mLongAttendees).addAttendees(mNoResponseAttendees); |
Isaac Katzenelson | fae6d5c | 2011-06-16 15:43:41 -0700 | [diff] [blame] | 1738 | mLongAttendees.setEnabled(false); |
| 1739 | mLongAttendees.setVisibility(View.VISIBLE); |
Isaac Katzenelson | 60f01c2 | 2011-06-03 15:42:01 -0700 | [diff] [blame] | 1740 | } else { |
Isaac Katzenelson | fae6d5c | 2011-06-16 15:43:41 -0700 | [diff] [blame] | 1741 | mLongAttendees.setVisibility(View.GONE); |
Michael Chan | 71b221a | 2010-10-25 17:55:44 -0700 | [diff] [blame] | 1742 | } |
Sara Ting | cb5f568 | 2012-04-04 22:52:20 -0700 | [diff] [blame] | 1743 | |
| 1744 | updateEmailAttendees(); |
| 1745 | } |
| 1746 | |
| 1747 | /** |
| 1748 | * Initializes the list of 'to' and 'cc' emails from the attendee list. |
| 1749 | */ |
| 1750 | private void updateEmailAttendees() { |
| 1751 | // The declined attendees will go in the 'cc' line, all others will go in the 'to' line. |
| 1752 | mToEmails = new ArrayList<String>(); |
| 1753 | for (Attendee attendee : mAcceptedAttendees) { |
| 1754 | addIfEmailable(mToEmails, attendee.mEmail); |
| 1755 | } |
| 1756 | for (Attendee attendee : mTentativeAttendees) { |
| 1757 | addIfEmailable(mToEmails, attendee.mEmail); |
| 1758 | } |
| 1759 | for (Attendee attendee : mNoResponseAttendees) { |
| 1760 | addIfEmailable(mToEmails, attendee.mEmail); |
| 1761 | } |
| 1762 | mCcEmails = new ArrayList<String>(); |
| 1763 | for (Attendee attendee : this.mDeclinedAttendees) { |
| 1764 | addIfEmailable(mCcEmails, attendee.mEmail); |
| 1765 | } |
| 1766 | |
| 1767 | // The meeting organizer doesn't appear as an attendee sometimes (particularly |
| 1768 | // when viewing someone else's calendar), so add the organizer now. |
Michael Chan | 83efa2d | 2012-04-24 17:42:21 -0700 | [diff] [blame] | 1769 | if (mEventOrganizerEmail != null && !mToEmails.contains(mEventOrganizerEmail) && |
| 1770 | !mCcEmails.contains(mEventOrganizerEmail)) { |
| 1771 | addIfEmailable(mToEmails, mEventOrganizerEmail); |
Sara Ting | cb5f568 | 2012-04-04 22:52:20 -0700 | [diff] [blame] | 1772 | } |
| 1773 | |
| 1774 | // The Email app behaves strangely when there is nothing in the 'mailto' part, |
| 1775 | // so move all the 'cc' emails to the 'to' list. Gmail works fine though. |
| 1776 | if (mToEmails.size() <= 0 && mCcEmails.size() > 0) { |
| 1777 | mToEmails.addAll(mCcEmails); |
| 1778 | mCcEmails.clear(); |
| 1779 | } |
| 1780 | |
| 1781 | if (mToEmails.size() <= 0) { |
| 1782 | setVisibilityCommon(mView, R.id.email_attendees_container, View.GONE); |
| 1783 | } else { |
| 1784 | setVisibilityCommon(mView, R.id.email_attendees_container, View.VISIBLE); |
| 1785 | } |
Michael Chan | 8ce3b7d | 2010-09-01 15:41:01 -0700 | [diff] [blame] | 1786 | } |
| 1787 | |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 1788 | public void initReminders(View view, Cursor cursor) { |
| 1789 | |
| 1790 | // Add reminders |
RoboErik | c7f3c38 | 2011-08-31 14:43:24 -0700 | [diff] [blame] | 1791 | mOriginalReminders.clear(); |
RoboErik | c08957b | 2011-09-09 13:43:38 -0700 | [diff] [blame] | 1792 | mUnsupportedReminders.clear(); |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 1793 | while (cursor.moveToNext()) { |
| 1794 | int minutes = cursor.getInt(EditEventHelper.REMINDERS_INDEX_MINUTES); |
| 1795 | int method = cursor.getInt(EditEventHelper.REMINDERS_INDEX_METHOD); |
RoboErik | e35a032 | 2011-09-01 16:21:49 -0700 | [diff] [blame] | 1796 | |
RoboErik | c08957b | 2011-09-09 13:43:38 -0700 | [diff] [blame] | 1797 | if (method != Reminders.METHOD_DEFAULT && !mReminderMethodValues.contains(method)) { |
RoboErik | e35a032 | 2011-09-01 16:21:49 -0700 | [diff] [blame] | 1798 | // Stash unsupported reminder types separately so we don't alter |
| 1799 | // them in the UI |
| 1800 | mUnsupportedReminders.add(ReminderEntry.valueOf(minutes, method)); |
| 1801 | } else { |
| 1802 | mOriginalReminders.add(ReminderEntry.valueOf(minutes, method)); |
| 1803 | } |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 1804 | } |
| 1805 | // Sort appropriately for display (by time, then type) |
| 1806 | Collections.sort(mOriginalReminders); |
| 1807 | |
RoboErik | 8b5743c | 2011-09-27 16:07:09 -0700 | [diff] [blame] | 1808 | if (mUserModifiedReminders) { |
| 1809 | // If the user has changed the list of reminders don't change what's |
| 1810 | // shown. |
| 1811 | return; |
| 1812 | } |
| 1813 | |
RoboErik | 5d40a38 | 2011-09-02 14:33:09 -0700 | [diff] [blame] | 1814 | LinearLayout parent = (LinearLayout) mScrollView |
| 1815 | .findViewById(R.id.reminder_items_container); |
| 1816 | if (parent != null) { |
| 1817 | parent.removeAllViews(); |
| 1818 | } |
RoboErik | c08957b | 2011-09-09 13:43:38 -0700 | [diff] [blame] | 1819 | if (mReminderViews != null) { |
| 1820 | mReminderViews.clear(); |
| 1821 | } |
RoboErik | 5d40a38 | 2011-09-02 14:33:09 -0700 | [diff] [blame] | 1822 | |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 1823 | if (mHasAlarm) { |
| 1824 | ArrayList<ReminderEntry> reminders = mOriginalReminders; |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 1825 | // Insert any minute values that aren't represented in the minutes list. |
| 1826 | for (ReminderEntry re : reminders) { |
| 1827 | EventViewUtils.addMinutesToList( |
| 1828 | mActivity, mReminderMinuteValues, mReminderMinuteLabels, re.getMinutes()); |
| 1829 | } |
| 1830 | // Create a UI element for each reminder. We display all of the reminders we get |
| 1831 | // from the provider, even if the count exceeds the calendar maximum. (Also, for |
| 1832 | // a new event, we won't have a maxReminders value available.) |
| 1833 | for (ReminderEntry re : reminders) { |
RoboErik | e35a032 | 2011-09-01 16:21:49 -0700 | [diff] [blame] | 1834 | EventViewUtils.addReminder(mActivity, mScrollView, this, mReminderViews, |
| 1835 | mReminderMinuteValues, mReminderMinuteLabels, mReminderMethodValues, |
RoboErik | 8b5743c | 2011-09-27 16:07:09 -0700 | [diff] [blame] | 1836 | mReminderMethodLabels, re, Integer.MAX_VALUE, mReminderChangeListener); |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 1837 | } |
Sara Ting | 06f3d6d | 2012-03-23 17:19:22 -0700 | [diff] [blame] | 1838 | EventViewUtils.updateAddReminderButton(mView, mReminderViews, mMaxReminders); |
RoboErik | e35a032 | 2011-09-01 16:21:49 -0700 | [diff] [blame] | 1839 | // TODO show unsupported reminder types in some fashion. |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 1840 | } |
| 1841 | } |
| 1842 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1843 | void updateResponse(View view) { |
| 1844 | // we only let the user accept/reject/etc. a meeting if: |
| 1845 | // a) you can edit the event's containing calendar AND |
| 1846 | // b) you're not the organizer and only attendee AND |
| 1847 | // c) organizerCanRespond is enabled for the calendar |
| 1848 | // (if the attendee data has been hidden, the visible number of attendees |
| 1849 | // will be 1 -- the calendar owner's). |
| 1850 | // (there are more cases involved to be 100% accurate, such as |
| 1851 | // paying attention to whether or not an attendee status was |
| 1852 | // included in the feed, but we're currently omitting those corner cases |
| 1853 | // for simplicity). |
Michael Chan | 352e1a2 | 2010-09-28 05:15:08 -0700 | [diff] [blame] | 1854 | |
| 1855 | // TODO Switch to EditEventHelper.canRespond when this class uses CalendarEventModel. |
Michael Chan | d785cd5 | 2010-09-03 13:57:19 -0700 | [diff] [blame] | 1856 | if (!mCanModifyCalendar || (mHasAttendeeData && mIsOrganizer && mNumOfAttendees <= 1) || |
Michael Chan | 352e1a2 | 2010-09-28 05:15:08 -0700 | [diff] [blame] | 1857 | (mIsOrganizer && !mOwnerCanRespond)) { |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1858 | setVisibilityCommon(view, R.id.response_container, View.GONE); |
| 1859 | return; |
| 1860 | } |
| 1861 | |
| 1862 | setVisibilityCommon(view, R.id.response_container, View.VISIBLE); |
| 1863 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1864 | |
Michael Chan | f92f46b | 2010-10-27 18:59:05 -0700 | [diff] [blame] | 1865 | int response; |
Isaac Katzenelson | 6bcafcf | 2012-05-02 18:25:36 -0700 | [diff] [blame] | 1866 | if (mUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) { |
RoboErik | 5afc083 | 2011-09-27 14:14:09 -0700 | [diff] [blame] | 1867 | response = mUserSetResponse; |
Isaac Katzenelson | 6bcafcf | 2012-05-02 18:25:36 -0700 | [diff] [blame] | 1868 | } else if (mAttendeeResponseFromIntent != Attendees.ATTENDEE_STATUS_NONE) { |
Michael Chan | f92f46b | 2010-10-27 18:59:05 -0700 | [diff] [blame] | 1869 | response = mAttendeeResponseFromIntent; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1870 | } else { |
Michael Chan | f92f46b | 2010-10-27 18:59:05 -0700 | [diff] [blame] | 1871 | response = mOriginalAttendeeResponse; |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1872 | } |
Michael Chan | f92f46b | 2010-10-27 18:59:05 -0700 | [diff] [blame] | 1873 | |
| 1874 | int buttonToCheck = findButtonIdForResponse(response); |
| 1875 | RadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.response_value); |
| 1876 | radioGroup.check(buttonToCheck); // -1 clear all radio buttons |
| 1877 | radioGroup.setOnCheckedChangeListener(this); |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 1878 | } |
| 1879 | |
| 1880 | private void setTextCommon(View view, int id, CharSequence text) { |
| 1881 | TextView textView = (TextView) view.findViewById(id); |
| 1882 | if (textView == null) |
| 1883 | return; |
| 1884 | textView.setText(text); |
| 1885 | } |
| 1886 | |
| 1887 | private void setVisibilityCommon(View view, int id, int visibility) { |
| 1888 | View v = view.findViewById(id); |
| 1889 | if (v != null) { |
| 1890 | v.setVisibility(visibility); |
| 1891 | } |
| 1892 | return; |
| 1893 | } |
| 1894 | |
| 1895 | /** |
| 1896 | * Taken from com.google.android.gm.HtmlConversationActivity |
| 1897 | * |
| 1898 | * Send the intent that shows the Contact info corresponding to the email address. |
| 1899 | */ |
| 1900 | public void showContactInfo(Attendee attendee, Rect rect) { |
| 1901 | // First perform lookup query to find existing contact |
| 1902 | final ContentResolver resolver = getActivity().getContentResolver(); |
| 1903 | final String address = attendee.mEmail; |
| 1904 | final Uri dataUri = Uri.withAppendedPath(CommonDataKinds.Email.CONTENT_FILTER_URI, |
| 1905 | Uri.encode(address)); |
| 1906 | final Uri lookupUri = ContactsContract.Data.getContactLookupUri(resolver, dataUri); |
| 1907 | |
| 1908 | if (lookupUri != null) { |
| 1909 | // Found matching contact, trigger QuickContact |
| 1910 | QuickContact.showQuickContact(getActivity(), rect, lookupUri, |
| 1911 | QuickContact.MODE_MEDIUM, null); |
| 1912 | } else { |
| 1913 | // No matching contact, ask user to create one |
| 1914 | final Uri mailUri = Uri.fromParts("mailto", address, null); |
| 1915 | final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, mailUri); |
| 1916 | |
| 1917 | // Pass along full E-mail string for possible create dialog |
| 1918 | Rfc822Token sender = new Rfc822Token(attendee.mName, attendee.mEmail, null); |
| 1919 | intent.putExtra(Intents.EXTRA_CREATE_DESCRIPTION, sender.toString()); |
| 1920 | |
| 1921 | // Only provide personal name hint if we have one |
| 1922 | final String senderPersonal = attendee.mName; |
| 1923 | if (!TextUtils.isEmpty(senderPersonal)) { |
| 1924 | intent.putExtra(Intents.Insert.NAME, senderPersonal); |
| 1925 | } |
| 1926 | |
| 1927 | startActivity(intent); |
| 1928 | } |
| 1929 | } |
Erik | cb81189 | 2010-09-28 13:44:19 -0700 | [diff] [blame] | 1930 | |
| 1931 | @Override |
RoboErik | 7c6236d | 2011-02-24 16:41:18 -0800 | [diff] [blame] | 1932 | public void onPause() { |
| 1933 | mIsPaused = true; |
| 1934 | mHandler.removeCallbacks(onDeleteRunnable); |
| 1935 | super.onPause(); |
Isaac Katzenelson | b0a313a | 2011-10-24 11:41:56 -0700 | [diff] [blame] | 1936 | // Remove event deletion alert box since it is being rebuild in the OnResume |
| 1937 | // This is done to get the same behavior on OnResume since the AlertDialog is gone on |
| 1938 | // rotation but not if you press the HOME key |
| 1939 | if (mDeleteDialogVisible && mDeleteHelper != null) { |
| 1940 | mDeleteHelper.dismissAlertDialog(); |
| 1941 | mDeleteHelper = null; |
| 1942 | } |
RoboErik | 7c6236d | 2011-02-24 16:41:18 -0800 | [diff] [blame] | 1943 | } |
| 1944 | |
| 1945 | @Override |
| 1946 | public void onResume() { |
| 1947 | super.onResume(); |
| 1948 | mIsPaused = false; |
| 1949 | if (mDismissOnResume) { |
| 1950 | mHandler.post(onDeleteRunnable); |
| 1951 | } |
Isaac Katzenelson | b0a313a | 2011-10-24 11:41:56 -0700 | [diff] [blame] | 1952 | // Display the "delete confirmation" dialog if needed |
| 1953 | if (mDeleteDialogVisible) { |
| 1954 | mDeleteHelper = new DeleteEventHelper( |
| 1955 | mContext, mActivity, |
| 1956 | !mIsDialog && !mIsTabletConfig /* exitWhenDone */); |
| 1957 | mDeleteHelper.setOnDismissListener(createDeleteOnDismissListener()); |
| 1958 | mDeleteHelper.delete(mStartMillis, mEndMillis, mEventId, -1, onDeleteRunnable); |
| 1959 | } |
RoboErik | 7c6236d | 2011-02-24 16:41:18 -0800 | [diff] [blame] | 1960 | } |
| 1961 | |
| 1962 | @Override |
Erik | cb81189 | 2010-09-28 13:44:19 -0700 | [diff] [blame] | 1963 | public void eventsChanged() { |
| 1964 | } |
| 1965 | |
| 1966 | @Override |
Erik | cb81189 | 2010-09-28 13:44:19 -0700 | [diff] [blame] | 1967 | public long getSupportedEventTypes() { |
| 1968 | return EventType.EVENTS_CHANGED; |
| 1969 | } |
| 1970 | |
| 1971 | @Override |
Erik | cb81189 | 2010-09-28 13:44:19 -0700 | [diff] [blame] | 1972 | public void handleEvent(EventInfo event) { |
RoboErik | f836d4a | 2011-07-22 17:01:27 -0700 | [diff] [blame] | 1973 | if (event.eventType == EventType.EVENTS_CHANGED && mHandler != null) { |
Erik | cb81189 | 2010-09-28 13:44:19 -0700 | [diff] [blame] | 1974 | // reload the data |
Isaac Katzenelson | 80d640f | 2012-04-20 09:21:28 -0700 | [diff] [blame] | 1975 | reloadEvents(); |
Erik | cb81189 | 2010-09-28 13:44:19 -0700 | [diff] [blame] | 1976 | } |
Erik | cb81189 | 2010-09-28 13:44:19 -0700 | [diff] [blame] | 1977 | } |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 1978 | |
Isaac Katzenelson | 80d640f | 2012-04-20 09:21:28 -0700 | [diff] [blame] | 1979 | public void reloadEvents() { |
| 1980 | mHandler.startQuery(TOKEN_QUERY_EVENT, null, mUri, EVENT_PROJECTION, |
| 1981 | null, null, null); |
| 1982 | } |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 1983 | |
| 1984 | @Override |
| 1985 | public void onClick(View view) { |
| 1986 | |
| 1987 | // This must be a click on one of the "remove reminder" buttons |
| 1988 | LinearLayout reminderItem = (LinearLayout) view.getParent(); |
| 1989 | LinearLayout parent = (LinearLayout) reminderItem.getParent(); |
| 1990 | parent.removeView(reminderItem); |
| 1991 | mReminderViews.remove(reminderItem); |
RoboErik | 8b5743c | 2011-09-27 16:07:09 -0700 | [diff] [blame] | 1992 | mUserModifiedReminders = true; |
Sara Ting | 06f3d6d | 2012-03-23 17:19:22 -0700 | [diff] [blame] | 1993 | EventViewUtils.updateAddReminderButton(mView, mReminderViews, mMaxReminders); |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 1994 | } |
| 1995 | |
| 1996 | |
| 1997 | /** |
| 1998 | * Add a new reminder when the user hits the "add reminder" button. We use the default |
| 1999 | * reminder time and method. |
| 2000 | */ |
| 2001 | private void addReminder() { |
| 2002 | // TODO: when adding a new reminder, make it different from the |
| 2003 | // last one in the list (if any). |
| 2004 | if (mDefaultReminderMinutes == GeneralPreferences.NO_REMINDER) { |
| 2005 | EventViewUtils.addReminder(mActivity, mScrollView, this, mReminderViews, |
RoboErik | 8b5743c | 2011-09-27 16:07:09 -0700 | [diff] [blame] | 2006 | mReminderMinuteValues, mReminderMinuteLabels, mReminderMethodValues, |
| 2007 | mReminderMethodLabels, |
| 2008 | ReminderEntry.valueOf(GeneralPreferences.REMINDER_DEFAULT_TIME), mMaxReminders, |
| 2009 | mReminderChangeListener); |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 2010 | } else { |
| 2011 | EventViewUtils.addReminder(mActivity, mScrollView, this, mReminderViews, |
RoboErik | 8b5743c | 2011-09-27 16:07:09 -0700 | [diff] [blame] | 2012 | mReminderMinuteValues, mReminderMinuteLabels, mReminderMethodValues, |
| 2013 | mReminderMethodLabels, ReminderEntry.valueOf(mDefaultReminderMinutes), |
| 2014 | mMaxReminders, mReminderChangeListener); |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 2015 | } |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 2016 | |
Sara Ting | 06f3d6d | 2012-03-23 17:19:22 -0700 | [diff] [blame] | 2017 | EventViewUtils.updateAddReminderButton(mView, mReminderViews, mMaxReminders); |
| 2018 | } |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 2019 | |
RoboErik | e35a032 | 2011-09-01 16:21:49 -0700 | [diff] [blame] | 2020 | synchronized private void prepareReminders() { |
| 2021 | // Nothing to do if we've already built these lists _and_ we aren't |
| 2022 | // removing not allowed methods |
| 2023 | if (mReminderMinuteValues != null && mReminderMinuteLabels != null |
| 2024 | && mReminderMethodValues != null && mReminderMethodLabels != null |
| 2025 | && mCalendarAllowedReminders == null) { |
| 2026 | return; |
| 2027 | } |
| 2028 | // Load the labels and corresponding numeric values for the minutes and methods lists |
| 2029 | // from the assets. If we're switching calendars, we need to clear and re-populate the |
| 2030 | // lists (which may have elements added and removed based on calendar properties). This |
| 2031 | // is mostly relevant for "methods", since we shouldn't have any "minutes" values in a |
| 2032 | // new event that aren't in the default set. |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 2033 | Resources r = mActivity.getResources(); |
| 2034 | mReminderMinuteValues = loadIntegerArray(r, R.array.reminder_minutes_values); |
| 2035 | mReminderMinuteLabels = loadStringArray(r, R.array.reminder_minutes_labels); |
| 2036 | mReminderMethodValues = loadIntegerArray(r, R.array.reminder_methods_values); |
| 2037 | mReminderMethodLabels = loadStringArray(r, R.array.reminder_methods_labels); |
RoboErik | e35a032 | 2011-09-01 16:21:49 -0700 | [diff] [blame] | 2038 | |
| 2039 | // Remove any reminder methods that aren't allowed for this calendar. If this is |
| 2040 | // a new event, mCalendarAllowedReminders may not be set the first time we're called. |
RoboErik | e35a032 | 2011-09-01 16:21:49 -0700 | [diff] [blame] | 2041 | if (mCalendarAllowedReminders != null) { |
| 2042 | EventViewUtils.reduceMethodList(mReminderMethodValues, mReminderMethodLabels, |
| 2043 | mCalendarAllowedReminders); |
| 2044 | } |
| 2045 | if (mView != null) { |
| 2046 | mView.invalidate(); |
| 2047 | } |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 2048 | } |
| 2049 | |
| 2050 | |
| 2051 | private boolean saveReminders() { |
| 2052 | ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(3); |
| 2053 | |
| 2054 | // Read reminders from UI |
| 2055 | mReminders = EventViewUtils.reminderItemsToReminders(mReminderViews, |
| 2056 | mReminderMinuteValues, mReminderMethodValues); |
RoboErik | e35a032 | 2011-09-01 16:21:49 -0700 | [diff] [blame] | 2057 | mOriginalReminders.addAll(mUnsupportedReminders); |
| 2058 | Collections.sort(mOriginalReminders); |
| 2059 | mReminders.addAll(mUnsupportedReminders); |
| 2060 | Collections.sort(mReminders); |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 2061 | |
| 2062 | // Check if there are any changes in the reminder |
| 2063 | boolean changed = EditEventHelper.saveReminders(ops, mEventId, mReminders, |
| 2064 | mOriginalReminders, false /* no force save */); |
| 2065 | |
| 2066 | if (!changed) { |
| 2067 | return false; |
| 2068 | } |
| 2069 | |
| 2070 | // save new reminders |
| 2071 | AsyncQueryService service = new AsyncQueryService(getActivity()); |
| 2072 | service.startBatch(0, null, Calendars.CONTENT_URI.getAuthority(), ops, 0); |
| 2073 | // Update the "hasAlarm" field for the event |
| 2074 | Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId); |
| 2075 | int len = mReminders.size(); |
| 2076 | boolean hasAlarm = len > 0; |
| 2077 | if (hasAlarm != mHasAlarm) { |
| 2078 | ContentValues values = new ContentValues(); |
| 2079 | values.put(Events.HAS_ALARM, hasAlarm ? 1 : 0); |
| 2080 | service.startUpdate(0, null, uri, values, null, null, 0); |
| 2081 | } |
| 2082 | return true; |
| 2083 | } |
| 2084 | |
| 2085 | /** |
Sara Ting | 42896f7 | 2012-03-15 15:24:36 -0700 | [diff] [blame] | 2086 | * Adds the attendee's email to the list if: |
| 2087 | * (1) the attendee is not a resource like a conference room or another calendar. |
| 2088 | * Catch most of these by filtering out suffix calendar.google.com. |
| 2089 | * (2) the attendee is not the viewer, to prevent mailing himself. |
| 2090 | */ |
| 2091 | private void addIfEmailable(ArrayList<String> emailList, String email) { |
Sara Ting | ddbc002 | 2012-04-26 17:08:46 -0700 | [diff] [blame] | 2092 | if (Utils.isValidEmail(email) && !email.equals(mSyncAccountName)) { |
Sara Ting | 42896f7 | 2012-03-15 15:24:36 -0700 | [diff] [blame] | 2093 | emailList.add(email); |
| 2094 | } |
| 2095 | } |
| 2096 | |
| 2097 | /** |
| 2098 | * Email all the attendees of the event, except for the viewer (so as to not email |
| 2099 | * himself) and resources like conference rooms. |
| 2100 | */ |
| 2101 | private void emailAttendees() { |
Sara Ting | d9d123d | 2012-04-23 15:50:46 -0700 | [diff] [blame] | 2102 | String eventTitle = (mTitle == null || mTitle.getText() == null) ? null : |
| 2103 | mTitle.getText().toString(); |
| 2104 | Intent emailIntent = Utils.createEmailAttendeesIntent(getActivity().getResources(), |
| 2105 | eventTitle, mToEmails, mCcEmails, mCalendarOwnerAccount); |
| 2106 | startActivity(emailIntent); |
Sara Ting | 42896f7 | 2012-03-15 15:24:36 -0700 | [diff] [blame] | 2107 | } |
| 2108 | |
| 2109 | /** |
Isaac Katzenelson | 1ce35aa | 2011-07-05 10:03:28 -0700 | [diff] [blame] | 2110 | * Loads an integer array asset into a list. |
| 2111 | */ |
| 2112 | private static ArrayList<Integer> loadIntegerArray(Resources r, int resNum) { |
| 2113 | int[] vals = r.getIntArray(resNum); |
| 2114 | int size = vals.length; |
| 2115 | ArrayList<Integer> list = new ArrayList<Integer>(size); |
| 2116 | |
| 2117 | for (int i = 0; i < size; i++) { |
| 2118 | list.add(vals[i]); |
| 2119 | } |
| 2120 | |
| 2121 | return list; |
| 2122 | } |
| 2123 | /** |
| 2124 | * Loads a String array asset into a list. |
| 2125 | */ |
| 2126 | private static ArrayList<String> loadStringArray(Resources r, int resNum) { |
| 2127 | String[] labels = r.getStringArray(resNum); |
| 2128 | ArrayList<String> list = new ArrayList<String>(Arrays.asList(labels)); |
| 2129 | return list; |
| 2130 | } |
| 2131 | |
Isaac Katzenelson | b33cdf4 | 2011-10-14 18:15:18 -0700 | [diff] [blame] | 2132 | public void onDeleteStarted() { |
| 2133 | mEventDeletionStarted = true; |
| 2134 | } |
| 2135 | |
Isaac Katzenelson | b0a313a | 2011-10-24 11:41:56 -0700 | [diff] [blame] | 2136 | private Dialog.OnDismissListener createDeleteOnDismissListener() { |
| 2137 | return new Dialog.OnDismissListener() { |
| 2138 | @Override |
| 2139 | public void onDismiss(DialogInterface dialog) { |
| 2140 | // Since OnPause will force the dialog to dismiss , do |
| 2141 | // not change the dialog status |
| 2142 | if (!mIsPaused) { |
| 2143 | mDeleteDialogVisible = false; |
| 2144 | } |
| 2145 | } |
| 2146 | }; |
| 2147 | } |
| 2148 | |
Isaac Katzenelson | 80d640f | 2012-04-20 09:21:28 -0700 | [diff] [blame] | 2149 | public long getEventId() { |
| 2150 | return mEventId; |
| 2151 | } |
| 2152 | |
| 2153 | public long getStartMillis() { |
| 2154 | return mStartMillis; |
| 2155 | } |
| 2156 | public long getEndMillis() { |
| 2157 | return mEndMillis; |
| 2158 | } |
| 2159 | |
| 2160 | |
| 2161 | |
Mason Tang | 2bebde7 | 2010-08-04 17:20:24 -0700 | [diff] [blame] | 2162 | } |