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