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.agenda;
18 
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.database.Cursor;
22 import android.provider.CalendarContract.Attendees;
23 import android.text.TextUtils;
24 import android.text.format.DateFormat;
25 import android.text.format.DateUtils;
26 import android.text.format.Time;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.widget.LinearLayout;
30 import android.widget.ResourceCursorAdapter;
31 import android.widget.TextView;
32 
33 import com.android.calendar.ColorChipView;
34 import com.android.calendar.R;
35 import com.android.calendar.Utils;
36 
37 import java.util.Formatter;
38 import java.util.Locale;
39 import java.util.TimeZone;
40 
41 public 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 
AgendaAdapter(Context context, int resource)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
bindView(View view, Context context, Cursor cursor)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