EventInfoActivity.java revision b84a151490b03c7083b8f517b83366bb11f17f51
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.calendar; 18 19import static android.provider.Calendar.EVENT_BEGIN_TIME; 20import static android.provider.Calendar.EVENT_END_TIME; 21import static android.provider.Calendar.AttendeesColumns.ATTENDEE_STATUS; 22 23import android.app.Activity; 24import android.content.ContentResolver; 25import android.content.ContentUris; 26import android.content.ContentValues; 27import android.content.Intent; 28import android.content.SharedPreferences; 29import android.content.res.Resources; 30import android.database.Cursor; 31import android.graphics.PorterDuff; 32import android.net.Uri; 33import android.os.Bundle; 34import android.pim.EventRecurrence; 35import android.preference.PreferenceManager; 36import android.provider.Calendar; 37import android.provider.Calendar.Attendees; 38import android.provider.Calendar.Calendars; 39import android.provider.Calendar.Events; 40import android.provider.Calendar.Reminders; 41import android.text.format.DateFormat; 42import android.text.format.DateUtils; 43import android.text.format.Time; 44import android.text.util.Linkify; 45import android.util.Log; 46import android.view.KeyEvent; 47import android.view.Menu; 48import android.view.MenuItem; 49import android.view.View; 50import android.widget.AdapterView; 51import android.widget.ArrayAdapter; 52import android.widget.ImageButton; 53import android.widget.LinearLayout; 54import android.widget.Spinner; 55import android.widget.TextView; 56import android.widget.Toast; 57 58import java.util.ArrayList; 59import java.util.Arrays; 60import java.util.regex.Pattern; 61 62public class EventInfoActivity extends Activity implements View.OnClickListener, 63 AdapterView.OnItemSelectedListener { 64 private static final int MAX_REMINDERS = 5; 65 66 /** 67 * These are the corresponding indices into the array of strings 68 * "R.array.change_response_labels" in the resource file. 69 */ 70 static final int UPDATE_SINGLE = 0; 71 static final int UPDATE_ALL = 1; 72 73 private static final String[] EVENT_PROJECTION = new String[] { 74 Events._ID, // 0 do not remove; used in DeleteEventHelper 75 Events.TITLE, // 1 do not remove; used in DeleteEventHelper 76 Events.RRULE, // 2 do not remove; used in DeleteEventHelper 77 Events.ALL_DAY, // 3 do not remove; used in DeleteEventHelper 78 Events.CALENDAR_ID, // 4 do not remove; used in DeleteEventHelper 79 Events.DTSTART, // 5 do not remove; used in DeleteEventHelper 80 Events._SYNC_ID, // 6 do not remove; used in DeleteEventHelper 81 Events.EVENT_TIMEZONE, // 7 do not remove; used in DeleteEventHelper 82 Events.DESCRIPTION, // 8 83 Events.EVENT_LOCATION, // 9 84 Events.HAS_ALARM, // 10 85 Events.ACCESS_LEVEL, // 11 86 Events.COLOR, // 12 87 }; 88 private static final int EVENT_INDEX_ID = 0; 89 private static final int EVENT_INDEX_TITLE = 1; 90 private static final int EVENT_INDEX_RRULE = 2; 91 private static final int EVENT_INDEX_ALL_DAY = 3; 92 private static final int EVENT_INDEX_CALENDAR_ID = 4; 93 private static final int EVENT_INDEX_SYNC_ID = 6; 94 private static final int EVENT_INDEX_EVENT_TIMEZONE = 7; 95 private static final int EVENT_INDEX_DESCRIPTION = 8; 96 private static final int EVENT_INDEX_EVENT_LOCATION = 9; 97 private static final int EVENT_INDEX_HAS_ALARM = 10; 98 private static final int EVENT_INDEX_ACCESS_LEVEL = 11; 99 private static final int EVENT_INDEX_COLOR = 12; 100 101 private static final String[] ATTENDEES_PROJECTION = new String[] { 102 Attendees._ID, // 0 103 Attendees.ATTENDEE_RELATIONSHIP, // 1 104 Attendees.ATTENDEE_STATUS, // 2 105 }; 106 private static final int ATTENDEES_INDEX_ID = 0; 107 private static final int ATTENDEES_INDEX_RELATIONSHIP = 1; 108 private static final int ATTENDEES_INDEX_STATUS = 2; 109 private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=%d"; 110 111 static final String[] CALENDARS_PROJECTION = new String[] { 112 Calendars._ID, // 0 113 Calendars.DISPLAY_NAME, // 1 114 }; 115 static final int CALENDARS_INDEX_DISPLAY_NAME = 1; 116 static final String CALENDARS_WHERE = Calendars._ID + "=%d"; 117 118 private static final String[] REMINDERS_PROJECTION = new String[] { 119 Reminders._ID, // 0 120 Reminders.MINUTES, // 1 121 }; 122 private static final int REMINDERS_INDEX_MINUTES = 1; 123 private static final String REMINDERS_WHERE = Reminders.EVENT_ID + "=%d AND (" + 124 Reminders.METHOD + "=" + Reminders.METHOD_ALERT + " OR " + Reminders.METHOD + "=" + 125 Reminders.METHOD_DEFAULT + ")"; 126 127 private static final int MENU_GROUP_REMINDER = 1; 128 private static final int MENU_GROUP_EDIT = 2; 129 private static final int MENU_GROUP_DELETE = 3; 130 131 private static final int MENU_ADD_REMINDER = 1; 132 private static final int MENU_EDIT = 2; 133 private static final int MENU_DELETE = 3; 134 135 private static final int ATTENDEE_NO_RESPONSE = -1; 136 private static final int[] ATTENDEE_VALUES = { 137 ATTENDEE_NO_RESPONSE, 138 Attendees.ATTENDEE_STATUS_ACCEPTED, 139 Attendees.ATTENDEE_STATUS_TENTATIVE, 140 Attendees.ATTENDEE_STATUS_DECLINED, 141 }; 142 143 private LinearLayout mRemindersContainer; 144 145 private Uri mUri; 146 private long mEventId; 147 private Cursor mEventCursor; 148 private Cursor mAttendeesCursor; 149 private Cursor mCalendarsCursor; 150 151 private long mStartMillis; 152 private long mEndMillis; 153 private int mVisibility = Calendars.NO_ACCESS; 154 private int mRelationship = Attendees.RELATIONSHIP_ORGANIZER; 155 156 private ArrayList<Integer> mOriginalMinutes = new ArrayList<Integer>(); 157 private ArrayList<LinearLayout> mReminderItems = new ArrayList<LinearLayout>(0); 158 private ArrayList<Integer> mReminderValues; 159 private ArrayList<String> mReminderLabels; 160 private int mDefaultReminderMinutes; 161 162 private DeleteEventHelper mDeleteEventHelper; 163 private EditResponseHelper mEditResponseHelper; 164 165 private int mResponseOffset; 166 private int mOriginalAttendeeResponse; 167 private int mAttendeeResponseFromIntent = ATTENDEE_NO_RESPONSE; 168 private boolean mIsRepeating; 169 170 private Pattern mWildcardPattern = Pattern.compile("^.*$"); 171 172 // This is called when one of the "remove reminder" buttons is selected. 173 public void onClick(View v) { 174 LinearLayout reminderItem = (LinearLayout) v.getParent(); 175 LinearLayout parent = (LinearLayout) reminderItem.getParent(); 176 parent.removeView(reminderItem); 177 mReminderItems.remove(reminderItem); 178 updateRemindersVisibility(); 179 } 180 181 public void onItemSelected(AdapterView parent, View v, int position, long id) { 182 // If they selected the "No response" option, then don't display the 183 // dialog asking which events to change. 184 if (id == 0 && mResponseOffset == 0) { 185 return; 186 } 187 188 // If this is not a repeating event, then don't display the dialog 189 // asking which events to change. 190 if (!mIsRepeating) { 191 return; 192 } 193 194 // If the selection is the same as the original, then don't display the 195 // dialog asking which events to change. 196 int index = findResponseIndexFor(mOriginalAttendeeResponse); 197 if (position == index + mResponseOffset) { 198 return; 199 } 200 201 // This is a repeating event. We need to ask the user if they mean to 202 // change just this one instance or all instances. 203 mEditResponseHelper.showDialog(mEditResponseHelper.getWhichEvents()); 204 } 205 206 public void onNothingSelected(AdapterView parent) { 207 } 208 209 @Override 210 protected void onCreate(Bundle icicle) { 211 super.onCreate(icicle); 212 213 // Event cursor 214 Intent intent = getIntent(); 215 mUri = intent.getData(); 216 ContentResolver cr = getContentResolver(); 217 mStartMillis = intent.getLongExtra(EVENT_BEGIN_TIME, 0); 218 mEndMillis = intent.getLongExtra(EVENT_END_TIME, 0); 219 mAttendeeResponseFromIntent = intent.getIntExtra(ATTENDEE_STATUS, ATTENDEE_NO_RESPONSE); 220 mEventCursor = managedQuery(mUri, EVENT_PROJECTION, null, null); 221 if (initEventCursor()) { 222 // The cursor is empty. This can happen if the event was deleted. 223 finish(); 224 return; 225 } 226 227 setContentView(R.layout.event_info_activity); 228 229 // Attendees cursor 230 Uri uri = Attendees.CONTENT_URI; 231 String where = String.format(ATTENDEES_WHERE, mEventId); 232 mAttendeesCursor = managedQuery(uri, ATTENDEES_PROJECTION, where, null); 233 initAttendeesCursor(); 234 235 // Calendars cursor 236 uri = Calendars.CONTENT_URI; 237 where = String.format(CALENDARS_WHERE, mEventCursor.getLong(EVENT_INDEX_CALENDAR_ID)); 238 mCalendarsCursor = managedQuery(uri, CALENDARS_PROJECTION, where, null); 239 initCalendarsCursor(); 240 241 Resources res = getResources(); 242 243 if (mVisibility >= Calendars.CONTRIBUTOR_ACCESS && 244 mRelationship == Attendees.RELATIONSHIP_ATTENDEE) { 245 setTitle(res.getString(R.string.event_info_title_invite)); 246 } else { 247 setTitle(res.getString(R.string.event_info_title)); 248 } 249 250 // Initialize the reminder values array. 251 Resources r = getResources(); 252 String[] strings = r.getStringArray(R.array.reminder_minutes_values); 253 int size = strings.length; 254 ArrayList<Integer> list = new ArrayList<Integer>(size); 255 for (int i = 0 ; i < size ; i++) { 256 list.add(Integer.parseInt(strings[i])); 257 } 258 mReminderValues = list; 259 String[] labels = r.getStringArray(R.array.reminder_minutes_labels); 260 mReminderLabels = new ArrayList<String>(Arrays.asList(labels)); 261 262 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 263 String durationString = 264 prefs.getString(CalendarPreferenceActivity.KEY_DEFAULT_REMINDER, "0"); 265 mDefaultReminderMinutes = Integer.parseInt(durationString); 266 267 mRemindersContainer = (LinearLayout) findViewById(R.id.reminder_items_container); 268 269 // Reminders cursor 270 boolean hasAlarm = mEventCursor.getInt(EVENT_INDEX_HAS_ALARM) != 0; 271 if (hasAlarm) { 272 uri = Reminders.CONTENT_URI; 273 where = String.format(REMINDERS_WHERE, mEventId); 274 Cursor reminderCursor = cr.query(uri, REMINDERS_PROJECTION, where, null, null); 275 try { 276 // First pass: collect all the custom reminder minutes (e.g., 277 // a reminder of 8 minutes) into a global list. 278 while (reminderCursor.moveToNext()) { 279 int minutes = reminderCursor.getInt(REMINDERS_INDEX_MINUTES); 280 EditEvent.addMinutesToList(this, mReminderValues, mReminderLabels, minutes); 281 } 282 283 // Second pass: create the reminder spinners 284 reminderCursor.moveToPosition(-1); 285 while (reminderCursor.moveToNext()) { 286 int minutes = reminderCursor.getInt(REMINDERS_INDEX_MINUTES); 287 mOriginalMinutes.add(minutes); 288 EditEvent.addReminder(this, this, mReminderItems, mReminderValues, 289 mReminderLabels, minutes); 290 } 291 } finally { 292 reminderCursor.close(); 293 } 294 } 295 296 updateView(); 297 updateRemindersVisibility(); 298 299 // Setup the + Add Reminder Button 300 View.OnClickListener addReminderOnClickListener = new View.OnClickListener() { 301 public void onClick(View v) { 302 addReminder(); 303 } 304 }; 305 ImageButton reminderRemoveButton = (ImageButton) findViewById(R.id.reminder_add); 306 reminderRemoveButton.setOnClickListener(addReminderOnClickListener); 307 308 mDeleteEventHelper = new DeleteEventHelper(this, true /* exit when done */); 309 mEditResponseHelper = new EditResponseHelper(this); 310 } 311 312 @Override 313 protected void onResume() { 314 super.onResume(); 315 if (initEventCursor()) { 316 // The cursor is empty. This can happen if the event was deleted. 317 finish(); 318 return; 319 } 320 initAttendeesCursor(); 321 initCalendarsCursor(); 322 } 323 324 /** 325 * Initializes the event cursor, which is expected to point to the first 326 * (and only) result from a query. 327 * @return true if the cursor is empty. 328 */ 329 private boolean initEventCursor() { 330 if ((mEventCursor == null) || (mEventCursor.getCount() == 0)) { 331 return true; 332 } 333 mEventCursor.moveToFirst(); 334 mVisibility = mEventCursor.getInt(EVENT_INDEX_ACCESS_LEVEL); 335 mEventId = mEventCursor.getInt(EVENT_INDEX_ID); 336 String rRule = mEventCursor.getString(EVENT_INDEX_RRULE); 337 mIsRepeating = (rRule != null); 338 return false; 339 } 340 341 private void initAttendeesCursor() { 342 if (mAttendeesCursor != null) { 343 if (mAttendeesCursor.moveToFirst()) { 344 mRelationship = mAttendeesCursor.getInt(ATTENDEES_INDEX_RELATIONSHIP); 345 } 346 } 347 } 348 349 private void initCalendarsCursor() { 350 if (mCalendarsCursor != null) { 351 mCalendarsCursor.moveToFirst(); 352 } 353 } 354 355 @Override 356 public void onPause() { 357 super.onPause(); 358 if (!isFinishing()) { 359 return; 360 } 361 ContentResolver cr = getContentResolver(); 362 ArrayList<Integer> reminderMinutes = EditEvent.reminderItemsToMinutes(mReminderItems, 363 mReminderValues); 364 boolean changed = EditEvent.saveReminders(cr, mEventId, reminderMinutes, mOriginalMinutes, 365 false /* no force save */); 366 changed |= saveResponse(cr); 367 if (changed) { 368 Toast.makeText(this, R.string.saving_event, Toast.LENGTH_SHORT).show(); 369 } 370 } 371 372 @Override 373 public boolean onCreateOptionsMenu(Menu menu) { 374 MenuItem item; 375 item = menu.add(MENU_GROUP_REMINDER, MENU_ADD_REMINDER, 0, 376 R.string.add_new_reminder); 377 item.setIcon(R.drawable.ic_menu_reminder); 378 item.setAlphabeticShortcut('r'); 379 380 item = menu.add(MENU_GROUP_EDIT, MENU_EDIT, 0, R.string.edit_event_label); 381 item.setIcon(android.R.drawable.ic_menu_edit); 382 item.setAlphabeticShortcut('e'); 383 384 item = menu.add(MENU_GROUP_DELETE, MENU_DELETE, 0, R.string.delete_event_label); 385 item.setIcon(android.R.drawable.ic_menu_delete); 386 387 return super.onCreateOptionsMenu(menu); 388 } 389 390 @Override 391 public boolean onPrepareOptionsMenu(Menu menu) { 392 // Cannot add reminders to a shared calendar with only free/busy 393 // permissions 394 if (mVisibility >= Calendars.READ_ACCESS && mReminderItems.size() < MAX_REMINDERS) { 395 menu.setGroupVisible(MENU_GROUP_REMINDER, true); 396 menu.setGroupEnabled(MENU_GROUP_REMINDER, true); 397 } else { 398 menu.setGroupVisible(MENU_GROUP_REMINDER, false); 399 menu.setGroupEnabled(MENU_GROUP_REMINDER, false); 400 } 401 402 if (mVisibility >= Calendars.CONTRIBUTOR_ACCESS && 403 mRelationship >= Attendees.RELATIONSHIP_ORGANIZER) { 404 menu.setGroupVisible(MENU_GROUP_EDIT, true); 405 menu.setGroupEnabled(MENU_GROUP_EDIT, true); 406 menu.setGroupVisible(MENU_GROUP_DELETE, true); 407 menu.setGroupEnabled(MENU_GROUP_DELETE, true); 408 } else { 409 menu.setGroupVisible(MENU_GROUP_EDIT, false); 410 menu.setGroupEnabled(MENU_GROUP_EDIT, false); 411 menu.setGroupVisible(MENU_GROUP_DELETE, false); 412 menu.setGroupEnabled(MENU_GROUP_DELETE, false); 413 } 414 415 return super.onPrepareOptionsMenu(menu); 416 } 417 418 private void addReminder() { 419 // TODO: when adding a new reminder, make it different from the 420 // last one in the list (if any). 421 if (mDefaultReminderMinutes == 0) { 422 EditEvent.addReminder(this, this, mReminderItems, 423 mReminderValues, mReminderLabels, 10 /* minutes */); 424 } else { 425 EditEvent.addReminder(this, this, mReminderItems, 426 mReminderValues, mReminderLabels, mDefaultReminderMinutes); 427 } 428 updateRemindersVisibility(); 429 } 430 431 @Override 432 public boolean onOptionsItemSelected(MenuItem item) { 433 super.onOptionsItemSelected(item); 434 switch (item.getItemId()) { 435 case MENU_ADD_REMINDER: 436 addReminder(); 437 break; 438 case MENU_EDIT: 439 doEdit(); 440 break; 441 case MENU_DELETE: 442 doDelete(); 443 break; 444 } 445 return true; 446 } 447 448 @Override 449 public boolean onKeyDown(int keyCode, KeyEvent event) { 450 if (keyCode == KeyEvent.KEYCODE_DEL) { 451 doDelete(); 452 return true; 453 } 454 return super.onKeyDown(keyCode, event); 455 } 456 457 private void updateRemindersVisibility() { 458 if (mReminderItems.size() == 0) { 459 mRemindersContainer.setVisibility(View.GONE); 460 } else { 461 mRemindersContainer.setVisibility(View.VISIBLE); 462 } 463 } 464 465 /** 466 * Saves the response to an invitation if the user changed the response. 467 * Returns true if the database was updated. 468 * 469 * @param cr the ContentResolver 470 * @return true if the database was changed 471 */ 472 private boolean saveResponse(ContentResolver cr) { 473 if (mAttendeesCursor == null || mEventCursor == null) { 474 return false; 475 } 476 Spinner spinner = (Spinner) findViewById(R.id.response_value); 477 int position = spinner.getSelectedItemPosition() - mResponseOffset; 478 if (position <= 0) { 479 return false; 480 } 481 482 int status = ATTENDEE_VALUES[position]; 483 484 // If the status has not changed, then don't update the database 485 if (status == mOriginalAttendeeResponse) { 486 return false; 487 } 488 489 long attendeeId = mAttendeesCursor.getInt(ATTENDEES_INDEX_ID); 490 if (!mIsRepeating) { 491 // This is a non-repeating event 492 updateResponse(cr, mEventId, attendeeId, status); 493 return true; 494 } 495 496 // This is a repeating event 497 int whichEvents = mEditResponseHelper.getWhichEvents(); 498 switch (whichEvents) { 499 case -1: 500 return false; 501 case UPDATE_SINGLE: 502 createExceptionResponse(cr, mEventId, attendeeId, status); 503 return true; 504 case UPDATE_ALL: 505 updateResponse(cr, mEventId, attendeeId, status); 506 return true; 507 default: 508 Log.e("Calendar", "Unexpected choice for updating invitation response"); 509 break; 510 } 511 return false; 512 } 513 514 private void updateResponse(ContentResolver cr, long eventId, long attendeeId, int status) { 515 // Update the "selfAttendeeStatus" field for the event 516 ContentValues values = new ContentValues(); 517 518 // Will need to add email when MULTIPLE_ATTENDEES_PER_EVENT supported. 519 values.put(Attendees.ATTENDEE_STATUS, status); 520 values.put(Attendees.EVENT_ID, eventId); 521 522 Uri uri = ContentUris.withAppendedId(Attendees.CONTENT_URI, attendeeId); 523 cr.update(uri, values, null /* where */, null /* selection args */); 524 } 525 526 private void createExceptionResponse(ContentResolver cr, long eventId, 527 long attendeeId, int status) { 528 // Fetch information about the repeating event. 529 Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId); 530 Cursor cursor = cr.query(uri, EVENT_PROJECTION, null, null, null); 531 if (cursor == null) { 532 return; 533 } 534 535 try { 536 cursor.moveToFirst(); 537 ContentValues values = new ContentValues(); 538 539 String title = cursor.getString(EVENT_INDEX_TITLE); 540 String timezone = cursor.getString(EVENT_INDEX_EVENT_TIMEZONE); 541 int calendarId = cursor.getInt(EVENT_INDEX_CALENDAR_ID); 542 boolean allDay = cursor.getInt(EVENT_INDEX_ALL_DAY) != 0; 543 String syncId = cursor.getString(EVENT_INDEX_SYNC_ID); 544 545 values.put(Events.TITLE, title); 546 values.put(Events.EVENT_TIMEZONE, timezone); 547 values.put(Events.ALL_DAY, allDay ? 1 : 0); 548 values.put(Events.CALENDAR_ID, calendarId); 549 values.put(Events.DTSTART, mStartMillis); 550 values.put(Events.DTEND, mEndMillis); 551 values.put(Events.ORIGINAL_EVENT, syncId); 552 values.put(Events.ORIGINAL_INSTANCE_TIME, mStartMillis); 553 values.put(Events.ORIGINAL_ALL_DAY, allDay ? 1 : 0); 554 values.put(Events.STATUS, Events.STATUS_CONFIRMED); 555 values.put(Events.SELF_ATTENDEE_STATUS, status); 556 557 // Create a recurrence exception 558 cr.insert(Events.CONTENT_URI, values); 559 } finally { 560 cursor.close(); 561 } 562 } 563 564 private int findResponseIndexFor(int response) { 565 int size = ATTENDEE_VALUES.length; 566 for (int index = 0; index < size; index++) { 567 if (ATTENDEE_VALUES[index] == response) { 568 return index; 569 } 570 } 571 return 0; 572 } 573 574 private void doEdit() { 575 Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, mEventId); 576 Intent intent = new Intent(Intent.ACTION_EDIT, uri); 577 intent.putExtra(Calendar.EVENT_BEGIN_TIME, mStartMillis); 578 intent.putExtra(Calendar.EVENT_END_TIME, mEndMillis); 579 intent.setClass(EventInfoActivity.this, EditEvent.class); 580 startActivity(intent); 581 finish(); 582 } 583 584 private void doDelete() { 585 mDeleteEventHelper.delete(mStartMillis, mEndMillis, mEventCursor, -1); 586 } 587 588 private void updateView() { 589 if (mEventCursor == null) { 590 return; 591 } 592 Resources res = getResources(); 593 594 String eventName = mEventCursor.getString(EVENT_INDEX_TITLE); 595 if (eventName == null || eventName.length() == 0) { 596 eventName = res.getString(R.string.no_title_label); 597 } 598 599 boolean allDay = mEventCursor.getInt(EVENT_INDEX_ALL_DAY) != 0; 600 String location = mEventCursor.getString(EVENT_INDEX_EVENT_LOCATION); 601 String description = mEventCursor.getString(EVENT_INDEX_DESCRIPTION); 602 String rRule = mEventCursor.getString(EVENT_INDEX_RRULE); 603 boolean hasAlarm = mEventCursor.getInt(EVENT_INDEX_HAS_ALARM) != 0; 604 String eventTimezone = mEventCursor.getString(EVENT_INDEX_EVENT_TIMEZONE); 605 int color = mEventCursor.getInt(EVENT_INDEX_COLOR) & 0xbbffffff; 606 607 View calBackground = findViewById(R.id.cal_background); 608 calBackground.setBackgroundColor(color); 609 610 TextView title = (TextView) findViewById(R.id.title); 611 title.setTextColor(color); 612 613 View divider = (View) findViewById(R.id.divider); 614 divider.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_IN); 615 616 // What 617 if (eventName != null) { 618 setTextCommon(R.id.title, eventName); 619 } 620 621 // When 622 String when; 623 int flags; 624 if (allDay) { 625 flags = DateUtils.FORMAT_UTC | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_DATE; 626 } else { 627 flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE; 628 if (DateFormat.is24HourFormat(this)) { 629 flags |= DateUtils.FORMAT_24HOUR; 630 } 631 } 632 when = DateUtils.formatDateRange(this, mStartMillis, mEndMillis, flags); 633 setTextCommon(R.id.when, when); 634 635 // Show the event timezone if it is different from the local timezone 636 Time time = new Time(); 637 String localTimezone = time.timezone; 638 if (allDay) { 639 localTimezone = Time.TIMEZONE_UTC; 640 } 641 if (eventTimezone != null && !localTimezone.equals(eventTimezone) && !allDay) { 642 setTextCommon(R.id.timezone, localTimezone); 643 } else { 644 setVisibilityCommon(R.id.timezone_container, View.GONE); 645 } 646 647 // Repeat 648 if (rRule != null) { 649 EventRecurrence eventRecurrence = new EventRecurrence(); 650 eventRecurrence.parse(rRule); 651 Time date = new Time(); 652 if (allDay) { 653 date.timezone = Time.TIMEZONE_UTC; 654 } 655 date.set(mStartMillis); 656 eventRecurrence.setStartDate(date); 657 String repeatString = eventRecurrence.getRepeatString(); 658 setTextCommon(R.id.repeat, repeatString); 659 } else { 660 setVisibilityCommon(R.id.repeat_container, View.GONE); 661 } 662 663 // Where 664 if (location == null || location.length() == 0) { 665 setVisibilityCommon(R.id.where, View.GONE); 666 } else { 667 TextView textView = (TextView) findViewById(R.id.where); 668 if (textView != null) { 669 textView.setAutoLinkMask(0); 670 textView.setText(location); 671 Linkify.addLinks(textView, mWildcardPattern, "geo:0,0?q="); 672 } 673 } 674 675 // Description 676 if (description == null || description.length() == 0) { 677 setVisibilityCommon(R.id.description, View.GONE); 678 } else { 679 setTextCommon(R.id.description, description); 680 } 681 682 // Calendar 683 if (mCalendarsCursor != null) { 684 mCalendarsCursor.moveToFirst(); 685 String calendarName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME); 686 setTextCommon(R.id.calendar, calendarName); 687 } else { 688 setVisibilityCommon(R.id.calendar_container, View.GONE); 689 } 690 691 // Response 692 updateResponse(); 693 } 694 695 void updateResponse() { 696 if (mVisibility < Calendars.CONTRIBUTOR_ACCESS || 697 mRelationship != Attendees.RELATIONSHIP_ATTENDEE) { 698 setVisibilityCommon(R.id.response_container, View.GONE); 699 return; 700 } 701 702 setVisibilityCommon(R.id.response_container, View.VISIBLE); 703 704 Spinner spinner = (Spinner) findViewById(R.id.response_value); 705 706 mOriginalAttendeeResponse = ATTENDEE_NO_RESPONSE; 707 if (mAttendeesCursor != null) { 708 mOriginalAttendeeResponse = mAttendeesCursor.getInt(ATTENDEES_INDEX_STATUS); 709 } 710 mResponseOffset = 0; 711 712 /* If the user has previously responded to this event 713 * we should not allow them to select no response again. 714 * Switch the entries to a set of entries without the 715 * no response option. 716 */ 717 if ((mOriginalAttendeeResponse != Attendees.ATTENDEE_STATUS_INVITED) 718 && (mOriginalAttendeeResponse != ATTENDEE_NO_RESPONSE) 719 && (mOriginalAttendeeResponse != Attendees.ATTENDEE_STATUS_NONE)) { 720 CharSequence[] entries; 721 entries = getResources().getTextArray(R.array.response_labels2); 722 mResponseOffset = -1; 723 ArrayAdapter<CharSequence> adapter = 724 new ArrayAdapter<CharSequence>(this, 725 android.R.layout.simple_spinner_item, entries); 726 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 727 spinner.setAdapter(adapter); 728 } 729 730 int index; 731 if (mAttendeeResponseFromIntent != ATTENDEE_NO_RESPONSE) { 732 index = findResponseIndexFor(mAttendeeResponseFromIntent); 733 } else { 734 index = findResponseIndexFor(mOriginalAttendeeResponse); 735 } 736 spinner.setSelection(index + mResponseOffset); 737 spinner.setOnItemSelectedListener(this); 738 } 739 740 private void setTextCommon(int id, CharSequence text) { 741 TextView textView = (TextView) findViewById(id); 742 if (textView == null) 743 return; 744 textView.setText(text); 745 } 746 747 private void setVisibilityCommon(int id, int visibility) { 748 View v = findViewById(id); 749 if (v != null) { 750 v.setVisibility(visibility); 751 } 752 return; 753 } 754} 755