1 /* 2 * Copyright (C) 2010 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.month; 18 19 import com.android.calendar.CalendarController; 20 import com.android.calendar.CalendarController.EventType; 21 import com.android.calendar.CalendarController.ViewType; 22 import com.android.calendar.Event; 23 import com.android.calendar.R; 24 import com.android.calendar.Utils; 25 26 import android.content.Context; 27 import android.content.res.Configuration; 28 import android.text.format.Time; 29 import android.util.Log; 30 import android.view.View; 31 import android.view.ViewGroup; 32 import android.widget.AbsListView.LayoutParams; 33 34 import java.util.ArrayList; 35 import java.util.HashMap; 36 37 public class MonthByWeekAdapter extends SimpleWeeksAdapter { 38 private static final String TAG = "MonthByWeek"; 39 40 public static final String WEEK_PARAMS_IS_MINI = "mini_month"; 41 protected static int DEFAULT_QUERY_DAYS = 7 * 8; // 8 weeks 42 private static final long ANIMATE_TODAY_TIMEOUT = 1000; 43 44 protected CalendarController mController; 45 protected String mHomeTimeZone; 46 protected Time mTempTime; 47 protected Time mToday; 48 protected int mFirstJulianDay; 49 protected int mQueryDays; 50 protected boolean mIsMiniMonth = true; 51 protected int mOrientation = Configuration.ORIENTATION_LANDSCAPE; 52 private boolean mShowAgendaWithMonth; 53 54 protected ArrayList<ArrayList<Event>> mEventDayList = new ArrayList<ArrayList<Event>>(); 55 protected ArrayList<Event> mEvents = null; 56 57 private boolean mAnimateToday = false; 58 private long mAnimateTime = 0; 59 60 public MonthByWeekAdapter(Context context, HashMap<String, Integer> params) { 61 super(context, params); 62 if (params.containsKey(WEEK_PARAMS_IS_MINI)) { 63 mIsMiniMonth = params.get(WEEK_PARAMS_IS_MINI) != 0; 64 } 65 mShowAgendaWithMonth = Utils.getConfigBool(context, R.bool.show_agenda_with_month); 66 } 67 68 public void animateToday() { 69 mAnimateToday = true; 70 mAnimateTime = System.currentTimeMillis(); 71 } 72 73 @Override 74 protected void init() { 75 super.init(); 76 mController = CalendarController.getInstance(mContext); 77 mHomeTimeZone = Utils.getTimeZone(mContext, null); 78 mSelectedDay.switchTimezone(mHomeTimeZone); 79 mToday = new Time(mHomeTimeZone); 80 mToday.setToNow(); 81 mTempTime = new Time(mHomeTimeZone); 82 } 83 84 private void updateTimeZones() { 85 mSelectedDay.timezone = mHomeTimeZone; 86 mSelectedDay.normalize(true); 87 mToday.timezone = mHomeTimeZone; 88 mToday.setToNow(); 89 mTempTime.switchTimezone(mHomeTimeZone); 90 } 91 92 @Override 93 public void setSelectedDay(Time selectedTime) { 94 mSelectedDay.set(selectedTime); 95 long millis = mSelectedDay.normalize(true); 96 mSelectedWeek = Utils.getWeeksSinceEpochFromJulianDay( 97 Time.getJulianDay(millis, mSelectedDay.gmtoff), mFirstDayOfWeek); 98 notifyDataSetChanged(); 99 } 100 101 public void setEvents(int firstJulianDay, int numDays, ArrayList<Event> events) { 102 if (mIsMiniMonth) { 103 if (Log.isLoggable(TAG, Log.ERROR)) { 104 Log.e(TAG, "Attempted to set events for mini view. Events only supported in full" 105 + " view."); 106 } 107 return; 108 } 109 mEvents = events; 110 mFirstJulianDay = firstJulianDay; 111 mQueryDays = numDays; 112 // Create a new list, this is necessary since the weeks are referencing 113 // pieces of the old list 114 ArrayList<ArrayList<Event>> eventDayList = new ArrayList<ArrayList<Event>>(); 115 for (int i = 0; i < numDays; i++) { 116 eventDayList.add(new ArrayList<Event>()); 117 } 118 119 if (events == null || events.size() == 0) { 120 if(Log.isLoggable(TAG, Log.DEBUG)) { 121 Log.d(TAG, "No events. Returning early--go schedule something fun."); 122 } 123 mEventDayList = eventDayList; 124 refresh(); 125 return; 126 } 127 128 // Compute the new set of days with events 129 for (Event event : events) { 130 int startDay = event.startDay - mFirstJulianDay; 131 int endDay = event.endDay - mFirstJulianDay + 1; 132 if (startDay < numDays || endDay >= 0) { 133 if (startDay < 0) { 134 startDay = 0; 135 } 136 if (startDay > numDays) { 137 continue; 138 } 139 if (endDay < 0) { 140 continue; 141 } 142 if (endDay > numDays) { 143 endDay = numDays; 144 } 145 for (int j = startDay; j < endDay; j++) { 146 eventDayList.get(j).add(event); 147 } 148 } 149 } 150 if(Log.isLoggable(TAG, Log.DEBUG)) { 151 Log.d(TAG, "Processed " + events.size() + " events."); 152 } 153 mEventDayList = eventDayList; 154 refresh(); 155 } 156 157 @SuppressWarnings("unchecked") 158 @Override 159 public View getView(int position, View convertView, ViewGroup parent) { 160 if (mIsMiniMonth) { 161 return super.getView(position, convertView, parent); 162 } 163 MonthWeekEventsView v; 164 LayoutParams params = new LayoutParams( 165 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 166 HashMap<String, Integer> drawingParams = null; 167 boolean isAnimatingToday = false; 168 if (convertView != null) { 169 v = (MonthWeekEventsView) convertView; 170 // Checking updateToday uses the current params instead of the new 171 // params, so this is assuming the view is relatively stable 172 if (mAnimateToday && v.updateToday(mSelectedDay.timezone)) { 173 long currentTime = System.currentTimeMillis(); 174 // If it's been too long since we tried to start the animation 175 // don't show it. This can happen if the user stops a scroll 176 // before reaching today. 177 if (currentTime - mAnimateTime > ANIMATE_TODAY_TIMEOUT) { 178 mAnimateToday = false; 179 mAnimateTime = 0; 180 } else { 181 isAnimatingToday = true; 182 // There is a bug that causes invalidates to not work some 183 // of the time unless we recreate the view. 184 v = new MonthWeekEventsView(mContext); 185 } 186 } else { 187 drawingParams = (HashMap<String, Integer>) v.getTag(); 188 } 189 } else { 190 v = new MonthWeekEventsView(mContext); 191 } 192 if (drawingParams == null) { 193 drawingParams = new HashMap<String, Integer>(); 194 } 195 drawingParams.clear(); 196 197 v.setLayoutParams(params); 198 v.setClickable(true); 199 v.setOnTouchListener(this); 200 201 int selectedDay = -1; 202 if (mSelectedWeek == position) { 203 selectedDay = mSelectedDay.weekDay; 204 } 205 206 drawingParams.put(SimpleWeekView.VIEW_PARAMS_HEIGHT, 207 (parent.getHeight() + parent.getTop()) / mNumWeeks); 208 drawingParams.put(SimpleWeekView.VIEW_PARAMS_SELECTED_DAY, selectedDay); 209 drawingParams.put(SimpleWeekView.VIEW_PARAMS_SHOW_WK_NUM, mShowWeekNumber ? 1 : 0); 210 drawingParams.put(SimpleWeekView.VIEW_PARAMS_WEEK_START, mFirstDayOfWeek); 211 drawingParams.put(SimpleWeekView.VIEW_PARAMS_NUM_DAYS, mDaysPerWeek); 212 drawingParams.put(SimpleWeekView.VIEW_PARAMS_WEEK, position); 213 drawingParams.put(SimpleWeekView.VIEW_PARAMS_FOCUS_MONTH, mFocusMonth); 214 drawingParams.put(MonthWeekEventsView.VIEW_PARAMS_ORIENTATION, mOrientation); 215 216 if (isAnimatingToday) { 217 drawingParams.put(MonthWeekEventsView.VIEW_PARAMS_ANIMATE_TODAY, 1); 218 mAnimateToday = false; 219 } 220 221 v.setWeekParams(drawingParams, mSelectedDay.timezone); 222 sendEventsToView(v); 223 return v; 224 } 225 226 private void sendEventsToView(MonthWeekEventsView v) { 227 if (mEventDayList.size() == 0) { 228 if (Log.isLoggable(TAG, Log.DEBUG)) { 229 Log.d(TAG, "No events loaded, did not pass any events to view."); 230 } 231 v.setEvents(null, null); 232 return; 233 } 234 int viewJulianDay = v.getFirstJulianDay(); 235 int start = viewJulianDay - mFirstJulianDay; 236 int end = start + v.mNumDays; 237 if (start < 0 || end > mEventDayList.size()) { 238 if (Log.isLoggable(TAG, Log.DEBUG)) { 239 Log.d(TAG, "Week is outside range of loaded events. viewStart: " + viewJulianDay 240 + " eventsStart: " + mFirstJulianDay); 241 } 242 v.setEvents(null, null); 243 return; 244 } 245 v.setEvents(mEventDayList.subList(start, end), mEvents); 246 } 247 248 @Override 249 protected void refresh() { 250 mFirstDayOfWeek = Utils.getFirstDayOfWeek(mContext); 251 mShowWeekNumber = Utils.getShowWeekNumber(mContext); 252 mHomeTimeZone = Utils.getTimeZone(mContext, null); 253 mOrientation = mContext.getResources().getConfiguration().orientation; 254 updateTimeZones(); 255 notifyDataSetChanged(); 256 } 257 258 @Override 259 protected void onDayTapped(Time day) { 260 day.timezone = mHomeTimeZone; 261 Time currTime = new Time(mHomeTimeZone); 262 currTime.set(mController.getTime()); 263 day.hour = currTime.hour; 264 day.minute = currTime.minute; 265 day.allDay = false; 266 day.normalize(true); 267 if (mShowAgendaWithMonth && !mIsMiniMonth) { 268 // If agenda view is visible with month view , refresh the views 269 // with the selected day's info 270 mController.sendEvent(mContext, EventType.GO_TO, day, day, -1, 271 ViewType.CURRENT, CalendarController.EXTRA_GOTO_DATE, null, null); 272 } else { 273 // Else , switch to the detailed view 274 mController.sendEvent(mContext, EventType.GO_TO, day, day, -1, 275 mIsMiniMonth ? ViewType.CURRENT : ViewType.DETAIL, 276 CalendarController.EXTRA_GOTO_DATE 277 | CalendarController.EXTRA_GOTO_BACK_TO_PREVIOUS, null, null); 278 } 279 } 280 281 } 282