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.agenda;
18
19import android.content.Context;
20import android.content.res.Resources;
21import android.database.Cursor;
22import android.provider.CalendarContract.Attendees;
23import android.text.TextUtils;
24import android.text.format.DateFormat;
25import android.text.format.DateUtils;
26import android.text.format.Time;
27import android.view.View;
28import android.view.ViewGroup;
29import android.widget.LinearLayout;
30import android.widget.ResourceCursorAdapter;
31import android.widget.TextView;
32
33import com.android.calendar.ColorChipView;
34import com.android.calendar.R;
35import com.android.calendar.Utils;
36
37import java.util.Formatter;
38import java.util.Locale;
39import java.util.TimeZone;
40
41public class AgendaAdapter extends ResourceCursorAdapter {
42    private final String mNoTitleLabel;
43    private final Resources mResources;
44    private final int mDeclinedColor;
45    private final int mStandardColor;
46    private final int mWhereColor;
47    private final int mWhereDeclinedColor;
48    // Note: Formatter is not thread safe. Fine for now as it is only used by the main thread.
49    private final Formatter mFormatter;
50    private final StringBuilder mStringBuilder;
51    private float mScale;
52
53    private int COLOR_CHIP_ALL_DAY_HEIGHT;
54    private int COLOR_CHIP_HEIGHT;
55
56    private final Runnable mTZUpdater = new Runnable() {
57        @Override
58        public void run() {
59            notifyDataSetChanged();
60        }
61    };
62
63    static class ViewHolder {
64
65        public static final int DECLINED_RESPONSE = 0;
66        public static final int TENTATIVE_RESPONSE = 1;
67        public static final int ACCEPTED_RESPONSE = 2;
68
69        /* Event */
70        TextView title;
71        TextView when;
72        TextView where;
73        View selectedMarker;
74        LinearLayout textContainer;
75        long instanceId;
76        ColorChipView colorChip;
77        long startTimeMilli;
78        boolean allDay;
79        boolean grayed;
80        int julianDay;
81    }
82
83    public AgendaAdapter(Context context, int resource) {
84        super(context, resource, null);
85
86        mResources = context.getResources();
87        mNoTitleLabel = mResources.getString(R.string.no_title_label);
88        mDeclinedColor = mResources.getColor(R.color.agenda_item_declined_color);
89        mStandardColor = mResources.getColor(R.color.agenda_item_standard_color);
90        mWhereDeclinedColor = mResources.getColor(R.color.agenda_item_where_declined_text_color);
91        mWhereColor = mResources.getColor(R.color.agenda_item_where_text_color);
92        mStringBuilder = new StringBuilder(50);
93        mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
94
95        COLOR_CHIP_ALL_DAY_HEIGHT = mResources.getInteger(R.integer.color_chip_all_day_height);
96        COLOR_CHIP_HEIGHT = mResources.getInteger(R.integer.color_chip_height);
97        if (mScale == 0) {
98            mScale = mResources.getDisplayMetrics().density;
99            if (mScale != 1) {
100                COLOR_CHIP_ALL_DAY_HEIGHT *= mScale;
101                COLOR_CHIP_HEIGHT *= mScale;
102            }
103        }
104
105    }
106
107    @Override
108    public void bindView(View view, Context context, Cursor cursor) {
109        ViewHolder holder = null;
110
111        // Listview may get confused and pass in a different type of view since
112        // we keep shifting data around. Not a big problem.
113        Object tag = view.getTag();
114        if (tag instanceof ViewHolder) {
115            holder = (ViewHolder) view.getTag();
116        }
117
118        if (holder == null) {
119            holder = new ViewHolder();
120            view.setTag(holder);
121            holder.title = (TextView) view.findViewById(R.id.title);
122            holder.when = (TextView) view.findViewById(R.id.when);
123            holder.where = (TextView) view.findViewById(R.id.where);
124            holder.textContainer = (LinearLayout)
125                    view.findViewById(R.id.agenda_item_text_container);
126            holder.selectedMarker = view.findViewById(R.id.selected_marker);
127            holder.colorChip = (ColorChipView)view.findViewById(R.id.agenda_item_color);
128        }
129
130        holder.startTimeMilli = cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
131        // Fade text if event was declined and set the color chip mode (response
132        boolean allDay = cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
133        holder.allDay = allDay;
134        int selfAttendeeStatus = cursor.getInt(AgendaWindowAdapter.INDEX_SELF_ATTENDEE_STATUS);
135        if (selfAttendeeStatus == Attendees.ATTENDEE_STATUS_DECLINED) {
136            holder.title.setTextColor(mDeclinedColor);
137            holder.when.setTextColor(mWhereDeclinedColor);
138            holder.where.setTextColor(mWhereDeclinedColor);
139            holder.colorChip.setDrawStyle(ColorChipView.DRAW_FADED);
140        } else {
141            holder.title.setTextColor(mStandardColor);
142            holder.when.setTextColor(mWhereColor);
143            holder.where.setTextColor(mWhereColor);
144            if (selfAttendeeStatus == Attendees.ATTENDEE_STATUS_INVITED) {
145                holder.colorChip.setDrawStyle(ColorChipView.DRAW_BORDER);
146            } else {
147                holder.colorChip.setDrawStyle(ColorChipView.DRAW_FULL);
148            }
149        }
150
151        // Set the size of the color chip
152        ViewGroup.LayoutParams params = holder.colorChip.getLayoutParams();
153        if (allDay) {
154            params.height = COLOR_CHIP_ALL_DAY_HEIGHT;
155        } else {
156            params.height = COLOR_CHIP_HEIGHT;
157
158        }
159        holder.colorChip.setLayoutParams(params);
160
161        // Deal with exchange events that the owner cannot respond to
162        int canRespond = cursor.getInt(AgendaWindowAdapter.INDEX_CAN_ORGANIZER_RESPOND);
163        if (canRespond == 0) {
164            String owner = cursor.getString(AgendaWindowAdapter.INDEX_OWNER_ACCOUNT);
165            String organizer = cursor.getString(AgendaWindowAdapter.INDEX_ORGANIZER);
166            if (owner.equals(organizer)) {
167                holder.colorChip.setDrawStyle(ColorChipView.DRAW_FULL);
168                holder.title.setTextColor(mStandardColor);
169                holder.when.setTextColor(mStandardColor);
170                holder.where.setTextColor(mStandardColor);
171            }
172        }
173
174        TextView title = holder.title;
175        TextView when = holder.when;
176        TextView where = holder.where;
177
178        holder.instanceId = cursor.getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID);
179
180        /* Calendar Color */
181        int color = Utils.getDisplayColorFromColor(cursor.getInt(AgendaWindowAdapter.INDEX_COLOR));
182        holder.colorChip.setColor(color);
183
184        // What
185        String titleString = cursor.getString(AgendaWindowAdapter.INDEX_TITLE);
186        if (titleString == null || titleString.length() == 0) {
187            titleString = mNoTitleLabel;
188        }
189        title.setText(titleString);
190
191        // When
192        long begin = cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
193        long end = cursor.getLong(AgendaWindowAdapter.INDEX_END);
194        String eventTz = cursor.getString(AgendaWindowAdapter.INDEX_TIME_ZONE);
195        int flags = 0;
196        String whenString;
197        // It's difficult to update all the adapters so just query this each
198        // time we need to build the view.
199        String tzString = Utils.getTimeZone(context, mTZUpdater);
200        if (allDay) {
201            tzString = Time.TIMEZONE_UTC;
202        } else {
203            flags = DateUtils.FORMAT_SHOW_TIME;
204        }
205        if (DateFormat.is24HourFormat(context)) {
206            flags |= DateUtils.FORMAT_24HOUR;
207        }
208        mStringBuilder.setLength(0);
209        whenString = DateUtils.formatDateRange(context, mFormatter, begin, end, flags, tzString)
210                .toString();
211        if (!allDay && !TextUtils.equals(tzString, eventTz)) {
212            String displayName;
213            // Figure out if this is in DST
214            Time date = new Time(tzString);
215            date.set(begin);
216
217            TimeZone tz = TimeZone.getTimeZone(tzString);
218            if (tz == null || tz.getID().equals("GMT")) {
219                displayName = tzString;
220            } else {
221                displayName = tz.getDisplayName(date.isDst != 0, TimeZone.SHORT);
222            }
223            whenString += " (" + displayName + ")";
224        }
225        when.setText(whenString);
226
227   /* Recurring event icon is removed
228        String rrule = cursor.getString(AgendaWindowAdapter.INDEX_RRULE);
229        if (!TextUtils.isEmpty(rrule)) {
230            when.setCompoundDrawablesWithIntrinsicBounds(null, null,
231                    context.getResources().getDrawable(R.drawable.ic_repeat_dark), null);
232            when.setCompoundDrawablePadding(5);
233        } else {
234            when.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
235        } */
236
237        /*
238        // Repeating info
239        View repeatContainer = view.findViewById(R.id.repeat_icon);
240        String rrule = cursor.getString(AgendaWindowAdapter.INDEX_RRULE);
241        if (!TextUtils.isEmpty(rrule)) {
242            repeatContainer.setVisibility(View.VISIBLE);
243        } else {
244            repeatContainer.setVisibility(View.GONE);
245        }
246        */
247
248        /*
249        // Reminder
250        boolean hasAlarm = cursor.getInt(AgendaWindowAdapter.INDEX_HAS_ALARM) != 0;
251        if (hasAlarm) {
252            updateReminder(view, context, begin, cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID));
253        }
254        */
255
256        // Where
257        String whereString = cursor.getString(AgendaWindowAdapter.INDEX_EVENT_LOCATION);
258        if (whereString != null && whereString.length() > 0) {
259            where.setVisibility(View.VISIBLE);
260            where.setText(whereString);
261        } else {
262            where.setVisibility(View.GONE);
263        }
264    }
265
266    /*
267    public static void updateReminder(View view, Context context, long begin, long eventId) {
268        ContentResolver cr = context.getContentResolver();
269        Uri uri = Reminders.CONTENT_URI;
270        String where = String.format(REMINDERS_WHERE, eventId);
271
272        Cursor remindersCursor = cr.query(uri, REMINDERS_PROJECTION, where, null, null);
273        if (remindersCursor != null) {
274            LayoutInflater inflater =
275                    (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
276            LinearLayout parent = (LinearLayout) view.findViewById(R.id.reminders_container);
277            parent.removeAllViews();
278            while (remindersCursor.moveToNext()) {
279                int alarm = remindersCursor.getInt(REMINDERS_INDEX_MINUTES);
280                String before = EditEvent.constructReminderLabel(context, alarm, true);
281                LinearLayout reminderItem = (LinearLayout)
282                        inflater.inflate(R.layout.agenda_reminder_item, null);
283                TextView reminderItemText = (TextView) reminderItem.findViewById(R.id.reminder);
284                reminderItemText.setText(before);
285                parent.addView(reminderItem);
286            }
287        }
288        remindersCursor.close();
289    }
290    */
291}
292
293