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 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 
    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      */
    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      */
    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      */
    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      */
    178     public Time getSelectedDay() {
    179         return mSelectedDay;
    180     }
    181 
    182     /**
    183      * updates any config options that may have changed and refreshes the view
    184      */
    185     protected void refresh() {
    186         notifyDataSetChanged();
    187     }
    188 
    189     @Override
    190     public int getCount() {
    191         return WEEK_COUNT;
    192     }
    193 
    194     @Override
    195     public Object getItem(int position) {
    196         return null;
    197     }
    198 
    199     @Override
    200     public long getItemId(int position) {
    201         return position;
    202     }
    203 
    204     @SuppressWarnings("unchecked")
    205     @Override
    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      */
    252     public void updateFocusMonth(int month) {
    253         mFocusMonth = month;
    254         notifyDataSetChanged();
    255     }
    256 
    257     @Override
    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      */
    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
    292         public boolean onSingleTapUp(MotionEvent e) {
    293             return true;
    294         }
    295     }
    296 
    297     ListView mListView;
    298 
    299     public void setListView(ListView lv) {
    300         mListView = lv;
    301     }
    302 }
    303