EventInfoActivity.java revision 98ab9de2fa5ad8dfd37faa6593dc66fa426d8960
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 android.app.Activity;
22import android.content.ContentResolver;
23import android.content.ContentUris;
24import android.content.ContentValues;
25import android.content.Intent;
26import android.content.SharedPreferences;
27import android.content.res.Resources;
28import android.database.Cursor;
29import android.graphics.PorterDuff;
30import android.net.Uri;
31import android.os.Bundle;
32import android.pim.EventRecurrence;
33import android.preference.PreferenceManager;
34import android.provider.Calendar;
35import android.provider.Calendar.Attendees;
36import android.provider.Calendar.Calendars;
37import android.provider.Calendar.Events;
38import android.provider.Calendar.Reminders;
39import android.text.format.DateFormat;
40import android.text.format.DateUtils;
41import android.text.format.Time;
42import android.util.Log;
43import android.view.KeyEvent;
44import android.view.Menu;
45import android.view.MenuItem;
46import android.view.View;
47import android.widget.AdapterView;
48import android.widget.ArrayAdapter;
49import android.widget.ImageButton;
50import android.widget.LinearLayout;
51import android.widget.Spinner;
52import android.widget.TextView;
53import android.widget.Toast;
54
55import java.util.ArrayList;
56import java.util.Arrays;
57
58public 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            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
586        String eventName = mEventCursor.getString(EVENT_INDEX_TITLE);
587        if (eventName == null || eventName.length() == 0) {
588            eventName = res.getString(R.string.no_title_label);
589        }
590
591        boolean allDay = mEventCursor.getInt(EVENT_INDEX_ALL_DAY) != 0;
592        String location = mEventCursor.getString(EVENT_INDEX_EVENT_LOCATION);
593        String description = mEventCursor.getString(EVENT_INDEX_DESCRIPTION);
594        String rRule = mEventCursor.getString(EVENT_INDEX_RRULE);
595        boolean hasAlarm = mEventCursor.getInt(EVENT_INDEX_HAS_ALARM) != 0;
596        String eventTimezone = mEventCursor.getString(EVENT_INDEX_EVENT_TIMEZONE);
597        int color = mEventCursor.getInt(EVENT_INDEX_COLOR) & 0xbbffffff;
598
599        View calBackground = findViewById(R.id.cal_background);
600        calBackground.setBackgroundColor(color);
601
602        TextView title = (TextView) findViewById(R.id.title);
603        title.setTextColor(color);
604
605        View divider = (View) findViewById(R.id.divider);
606        divider.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_IN);
607
608        // What
609        if (eventName != null) {
610            setTextCommon(R.id.title, eventName);
611        }
612
613        // When
614        String when;
615        int flags;
616        if (allDay) {
617            flags = DateUtils.FORMAT_UTC | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_DATE;
618        } else {
619            flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE;
620            if (DateFormat.is24HourFormat(this)) {
621                flags |= DateUtils.FORMAT_24HOUR;
622            }
623        }
624        when = DateUtils.formatDateRange(this, mStartMillis, mEndMillis, flags);
625        setTextCommon(R.id.when, when);
626
627        // Show the event timezone if it is different from the local timezone
628        Time time = new Time();
629        String localTimezone = time.timezone;
630        if (allDay) {
631            localTimezone = Time.TIMEZONE_UTC;
632        }
633        if (eventTimezone != null && !localTimezone.equals(eventTimezone) && !allDay) {
634            setTextCommon(R.id.timezone, localTimezone);
635        } else {
636            setVisibilityCommon(R.id.timezone_container, View.GONE);
637        }
638
639        // Repeat
640        if (rRule != null) {
641            EventRecurrence eventRecurrence = new EventRecurrence();
642            eventRecurrence.parse(rRule);
643            Time date = new Time();
644            if (allDay) {
645                date.timezone = Time.TIMEZONE_UTC;
646            }
647            date.set(mStartMillis);
648            eventRecurrence.setStartDate(date);
649            String repeatString = eventRecurrence.getRepeatString();
650            setTextCommon(R.id.repeat, repeatString);
651        } else {
652            setVisibilityCommon(R.id.repeat_container, View.GONE);
653        }
654
655        // Where
656        if (location == null || location.length() == 0) {
657            setVisibilityCommon(R.id.where, View.GONE);
658        } else {
659            setTextCommon(R.id.where, location);
660        }
661
662        // Description
663        if (description == null || description.length() == 0) {
664            setVisibilityCommon(R.id.description, View.GONE);
665        } else {
666            setTextCommon(R.id.description, description);
667        }
668
669        // Calendar
670        if (mCalendarsCursor != null) {
671            mCalendarsCursor.moveToFirst();
672            String calendarName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
673            setTextCommon(R.id.calendar, calendarName);
674        } else {
675            setVisibilityCommon(R.id.calendar_container, View.GONE);
676        }
677
678        // Response
679        updateResponse();
680    }
681
682    void updateResponse() {
683        if (mVisibility < Calendars.CONTRIBUTOR_ACCESS ||
684                mRelationship != Attendees.RELATIONSHIP_ATTENDEE) {
685            setVisibilityCommon(R.id.response_container, View.GONE);
686            return;
687        }
688
689        setVisibilityCommon(R.id.response_container, View.VISIBLE);
690
691        Spinner spinner = (Spinner) findViewById(R.id.response_value);
692
693        mOriginalAttendeeResponse = ATTENDEE_NO_RESPONSE;
694        if (mAttendeesCursor != null) {
695            mOriginalAttendeeResponse = mAttendeesCursor.getInt(ATTENDEES_INDEX_STATUS);
696        }
697        mResponseOffset = 0;
698
699        /* If the user has previously responded to this event
700         * we should not allow them to select no response again.
701         * Switch the entries to a set of entries without the
702         * no response option.
703         */
704        if ((mOriginalAttendeeResponse != Attendees.ATTENDEE_STATUS_INVITED)
705                && (mOriginalAttendeeResponse != ATTENDEE_NO_RESPONSE)
706                && (mOriginalAttendeeResponse != Attendees.ATTENDEE_STATUS_NONE)) {
707            CharSequence[] entries;
708            entries = getResources().getTextArray(R.array.response_labels2);
709            mResponseOffset = -1;
710            ArrayAdapter<CharSequence> adapter =
711                new ArrayAdapter<CharSequence>(this,
712                        android.R.layout.simple_spinner_item, entries);
713            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
714            spinner.setAdapter(adapter);
715        }
716
717        int index = findResponseIndexFor(mOriginalAttendeeResponse);
718        spinner.setSelection(index + mResponseOffset);
719        spinner.setOnItemSelectedListener(this);
720    }
721
722    private void setTextCommon(int id, CharSequence text) {
723        TextView textView = (TextView) findViewById(id);
724        if (textView == null)
725            return;
726        textView.setText(text);
727    }
728
729    private void setVisibilityCommon(int id, int visibility) {
730        View v = findViewById(id);
731        if (v != null) {
732            v.setVisibility(visibility);
733        }
734        return;
735    }
736}
737