OSDN Git Service

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