OSDN Git Service

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