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 // TODO Remove calendar imports when the required methods have been 20 // refactored into the public api 21 import com.android.calendar.CalendarController; 22 import com.android.calendar.Utils; 23 24 import android.content.Context; 25 import android.text.format.Time; 26 import android.util.Log; 27 import android.view.GestureDetector; 28 import android.view.MotionEvent; 29 import android.view.View; 30 import android.view.View.OnTouchListener; 31 import android.view.ViewGroup; 32 import android.widget.AbsListView.LayoutParams; 33 import android.widget.BaseAdapter; 34 import android.widget.ListView; 35 36 import java.util.Calendar; 37 import java.util.HashMap; 38 import java.util.Locale; 39 40 /** 41 * <p> 42 * This is a specialized adapter for creating a list of weeks with selectable 43 * days. It can be configured to display the week number, start the week on a 44 * given day, show a reduced number of days, or display an arbitrary number of 45 * weeks at a time. See {@link SimpleDayPickerFragment} for usage. 46 * </p> 47 */ 48 public class SimpleWeeksAdapter extends BaseAdapter implements OnTouchListener { 49 50 private static final String TAG = "MonthByWeek"; 51 52 /** 53 * The number of weeks to display at a time. 54 */ 55 public static final String WEEK_PARAMS_NUM_WEEKS = "num_weeks"; 56 /** 57 * Which month should be in focus currently. 58 */ 59 public static final String WEEK_PARAMS_FOCUS_MONTH = "focus_month"; 60 /** 61 * Whether the week number should be shown. Non-zero to show them. 62 */ 63 public static final String WEEK_PARAMS_SHOW_WEEK = "week_numbers"; 64 /** 65 * Which day the week should start on. {@link Time#SUNDAY} through 66 * {@link Time#SATURDAY}. 67 */ 68 public static final String WEEK_PARAMS_WEEK_START = "week_start"; 69 /** 70 * The Julian day to highlight as selected. 71 */ 72 public static final String WEEK_PARAMS_JULIAN_DAY = "selected_day"; 73 /** 74 * How many days of the week to display [1-7]. 75 */ 76 public static final String WEEK_PARAMS_DAYS_PER_WEEK = "days_per_week"; 77 78 protected static final int WEEK_COUNT = CalendarController.MAX_CALENDAR_WEEK 79 - CalendarController.MIN_CALENDAR_WEEK; 80 protected static int DEFAULT_NUM_WEEKS = 6; 81 protected static int DEFAULT_MONTH_FOCUS = 0; 82 protected static int DEFAULT_DAYS_PER_WEEK = 7; 83 protected static int DEFAULT_WEEK_HEIGHT = 32; 84 protected static int WEEK_7_OVERHANG_HEIGHT = 7; 85 86 protected static float mScale = 0; 87 protected Context mContext; 88 // The day to highlight as selected 89 protected Time mSelectedDay; 90 // The week since 1970 that the selected day is in 91 protected int mSelectedWeek; 92 // When the week starts; numbered like Time.<WEEKDAY> (e.g. SUNDAY=0). 93 protected int mFirstDayOfWeek; 94 protected boolean mShowWeekNumber = false; 95 protected GestureDetector mGestureDetector; 96 protected int mNumWeeks = DEFAULT_NUM_WEEKS; 97 protected int mDaysPerWeek = DEFAULT_DAYS_PER_WEEK; 98 protected int mFocusMonth = DEFAULT_MONTH_FOCUS; 99 SimpleWeeksAdapter(Context context, HashMap<String, Integer> params)100 public SimpleWeeksAdapter(Context context, HashMap<String, Integer> params) { 101 mContext = context; 102 103 // Get default week start based on locale, subtracting one for use with android Time. 104 Calendar cal = Calendar.getInstance(Locale.getDefault()); 105 mFirstDayOfWeek = cal.getFirstDayOfWeek() - 1; 106 107 if (mScale == 0) { 108 mScale = context.getResources().getDisplayMetrics().density; 109 if (mScale != 1) { 110 WEEK_7_OVERHANG_HEIGHT *= mScale; 111 } 112 } 113 init(); 114 updateParams(params); 115 } 116 117 /** 118 * Set up the gesture detector and selected time 119 */ init()120 protected void init() { 121 mGestureDetector = new GestureDetector(mContext, new CalendarGestureListener()); 122 mSelectedDay = new Time(); 123 mSelectedDay.setToNow(); 124 } 125 126 /** 127 * Parse the parameters and set any necessary fields. See 128 * {@link #WEEK_PARAMS_NUM_WEEKS} for parameter details. 129 * 130 * @param params A list of parameters for this adapter 131 */ updateParams(HashMap<String, Integer> params)132 public void updateParams(HashMap<String, Integer> params) { 133 if (params == null) { 134 Log.e(TAG, "WeekParameters are null! Cannot update adapter."); 135 return; 136 } 137 if (params.containsKey(WEEK_PARAMS_FOCUS_MONTH)) { 138 mFocusMonth = params.get(WEEK_PARAMS_FOCUS_MONTH); 139 } 140 if (params.containsKey(WEEK_PARAMS_FOCUS_MONTH)) { 141 mNumWeeks = params.get(WEEK_PARAMS_NUM_WEEKS); 142 } 143 if (params.containsKey(WEEK_PARAMS_SHOW_WEEK)) { 144 mShowWeekNumber = params.get(WEEK_PARAMS_SHOW_WEEK) != 0; 145 } 146 if (params.containsKey(WEEK_PARAMS_WEEK_START)) { 147 mFirstDayOfWeek = params.get(WEEK_PARAMS_WEEK_START); 148 } 149 if (params.containsKey(WEEK_PARAMS_JULIAN_DAY)) { 150 int julianDay = params.get(WEEK_PARAMS_JULIAN_DAY); 151 mSelectedDay.setJulianDay(julianDay); 152 mSelectedWeek = Utils.getWeeksSinceEpochFromJulianDay(julianDay, mFirstDayOfWeek); 153 } 154 if (params.containsKey(WEEK_PARAMS_DAYS_PER_WEEK)) { 155 mDaysPerWeek = params.get(WEEK_PARAMS_DAYS_PER_WEEK); 156 } 157 refresh(); 158 } 159 160 /** 161 * Updates the selected day and related parameters. 162 * 163 * @param selectedTime The time to highlight 164 */ setSelectedDay(Time selectedTime)165 public void setSelectedDay(Time selectedTime) { 166 mSelectedDay.set(selectedTime); 167 long millis = mSelectedDay.normalize(true); 168 mSelectedWeek = Utils.getWeeksSinceEpochFromJulianDay( 169 Time.getJulianDay(millis, mSelectedDay.gmtoff), mFirstDayOfWeek); 170 notifyDataSetChanged(); 171 } 172 173 /** 174 * Returns the currently highlighted day 175 * 176 * @return 177 */ getSelectedDay()178 public Time getSelectedDay() { 179 return mSelectedDay; 180 } 181 182 /** 183 * updates any config options that may have changed and refreshes the view 184 */ refresh()185 protected void refresh() { 186 notifyDataSetChanged(); 187 } 188 189 @Override getCount()190 public int getCount() { 191 return WEEK_COUNT; 192 } 193 194 @Override getItem(int position)195 public Object getItem(int position) { 196 return null; 197 } 198 199 @Override getItemId(int position)200 public long getItemId(int position) { 201 return position; 202 } 203 204 @SuppressWarnings("unchecked") 205 @Override getView(int position, View convertView, ViewGroup parent)206 public View getView(int position, View convertView, ViewGroup parent) { 207 SimpleWeekView v; 208 HashMap<String, Integer> drawingParams = null; 209 if (convertView != null) { 210 v = (SimpleWeekView) convertView; 211 // We store the drawing parameters in the view so it can be recycled 212 drawingParams = (HashMap<String, Integer>) v.getTag(); 213 } else { 214 v = new SimpleWeekView(mContext); 215 // Set up the new view 216 LayoutParams params = new LayoutParams( 217 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 218 v.setLayoutParams(params); 219 v.setClickable(true); 220 v.setOnTouchListener(this); 221 } 222 if (drawingParams == null) { 223 drawingParams = new HashMap<String, Integer>(); 224 } 225 drawingParams.clear(); 226 227 int selectedDay = -1; 228 if (mSelectedWeek == position) { 229 selectedDay = mSelectedDay.weekDay; 230 } 231 232 // pass in all the view parameters 233 drawingParams.put(SimpleWeekView.VIEW_PARAMS_HEIGHT, 234 (parent.getHeight() - WEEK_7_OVERHANG_HEIGHT) / mNumWeeks); 235 drawingParams.put(SimpleWeekView.VIEW_PARAMS_SELECTED_DAY, selectedDay); 236 drawingParams.put(SimpleWeekView.VIEW_PARAMS_SHOW_WK_NUM, mShowWeekNumber ? 1 : 0); 237 drawingParams.put(SimpleWeekView.VIEW_PARAMS_WEEK_START, mFirstDayOfWeek); 238 drawingParams.put(SimpleWeekView.VIEW_PARAMS_NUM_DAYS, mDaysPerWeek); 239 drawingParams.put(SimpleWeekView.VIEW_PARAMS_WEEK, position); 240 drawingParams.put(SimpleWeekView.VIEW_PARAMS_FOCUS_MONTH, mFocusMonth); 241 v.setWeekParams(drawingParams, mSelectedDay.timezone); 242 v.invalidate(); 243 244 return v; 245 } 246 247 /** 248 * Changes which month is in focus and updates the view. 249 * 250 * @param month The month to show as in focus [0-11] 251 */ updateFocusMonth(int month)252 public void updateFocusMonth(int month) { 253 mFocusMonth = month; 254 notifyDataSetChanged(); 255 } 256 257 @Override onTouch(View v, MotionEvent event)258 public boolean onTouch(View v, MotionEvent event) { 259 if (mGestureDetector.onTouchEvent(event)) { 260 SimpleWeekView view = (SimpleWeekView) v; 261 Time day = ((SimpleWeekView)v).getDayFromLocation(event.getX()); 262 if (Log.isLoggable(TAG, Log.DEBUG)) { 263 Log.d(TAG, "Touched day at Row=" + view.mWeek + " day=" + day.toString()); 264 } 265 if (day != null) { 266 onDayTapped(day); 267 } 268 return true; 269 } 270 return false; 271 } 272 273 /** 274 * Maintains the same hour/min/sec but moves the day to the tapped day. 275 * 276 * @param day The day that was tapped 277 */ onDayTapped(Time day)278 protected void onDayTapped(Time day) { 279 day.hour = mSelectedDay.hour; 280 day.minute = mSelectedDay.minute; 281 day.second = mSelectedDay.second; 282 setSelectedDay(day); 283 } 284 285 286 /** 287 * This is here so we can identify single tap events and set the selected 288 * day correctly 289 */ 290 protected class CalendarGestureListener extends GestureDetector.SimpleOnGestureListener { 291 @Override onSingleTapUp(MotionEvent e)292 public boolean onSingleTapUp(MotionEvent e) { 293 return true; 294 } 295 } 296 297 ListView mListView; 298 setListView(ListView lv)299 public void setListView(ListView lv) { 300 mListView = lv; 301 } 302 } 303