Home | History | Annotate | Download | only in widget
      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 android.widget;
     18 
     19 import android.annotation.Widget;
     20 import android.content.Context;
     21 import android.content.res.Configuration;
     22 import android.content.res.TypedArray;
     23 import android.graphics.drawable.Drawable;
     24 import android.util.AttributeSet;
     25 import android.util.Log;
     26 import android.view.accessibility.AccessibilityEvent;
     27 import android.view.accessibility.AccessibilityNodeInfo;
     28 
     29 import com.android.internal.R;
     30 
     31 import java.text.DateFormat;
     32 import java.text.ParseException;
     33 import java.text.SimpleDateFormat;
     34 import java.util.Calendar;
     35 import java.util.Locale;
     36 import java.util.TimeZone;
     37 
     38 /**
     39  * This class is a calendar widget for displaying and selecting dates. The range
     40  * of dates supported by this calendar is configurable. A user can select a date
     41  * by taping on it and can scroll and fling the calendar to a desired date.
     42  *
     43  * @attr ref android.R.styleable#CalendarView_showWeekNumber
     44  * @attr ref android.R.styleable#CalendarView_firstDayOfWeek
     45  * @attr ref android.R.styleable#CalendarView_minDate
     46  * @attr ref android.R.styleable#CalendarView_maxDate
     47  * @attr ref android.R.styleable#CalendarView_shownWeekCount
     48  * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor
     49  * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor
     50  * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor
     51  * @attr ref android.R.styleable#CalendarView_weekNumberColor
     52  * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor
     53  * @attr ref android.R.styleable#CalendarView_selectedDateVerticalBar
     54  * @attr ref android.R.styleable#CalendarView_weekDayTextAppearance
     55  * @attr ref android.R.styleable#CalendarView_dateTextAppearance
     56  */
     57 @Widget
     58 public class CalendarView extends FrameLayout {
     59     private static final String LOG_TAG = "CalendarView";
     60 
     61     private static final int MODE_HOLO = 0;
     62     private static final int MODE_MATERIAL = 1;
     63 
     64     private final CalendarViewDelegate mDelegate;
     65 
     66     /**
     67      * The callback used to indicate the user changes the date.
     68      */
     69     public interface OnDateChangeListener {
     70 
     71         /**
     72          * Called upon change of the selected day.
     73          *
     74          * @param view The view associated with this listener.
     75          * @param year The year that was set.
     76          * @param month The month that was set [0-11].
     77          * @param dayOfMonth The day of the month that was set.
     78          */
     79         public void onSelectedDayChange(CalendarView view, int year, int month, int dayOfMonth);
     80     }
     81 
     82     public CalendarView(Context context) {
     83         this(context, null);
     84     }
     85 
     86     public CalendarView(Context context, AttributeSet attrs) {
     87         this(context, attrs, R.attr.calendarViewStyle);
     88     }
     89 
     90     public CalendarView(Context context, AttributeSet attrs, int defStyleAttr) {
     91         this(context, attrs, defStyleAttr, 0);
     92     }
     93 
     94     public CalendarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
     95         super(context, attrs, defStyleAttr, defStyleRes);
     96 
     97         final TypedArray a = context.obtainStyledAttributes(
     98                 attrs, R.styleable.CalendarView, defStyleAttr, defStyleRes);
     99         final int mode = a.getInt(R.styleable.CalendarView_calendarViewMode, MODE_HOLO);
    100         a.recycle();
    101 
    102         switch (mode) {
    103             case MODE_HOLO:
    104                 mDelegate = new CalendarViewLegacyDelegate(
    105                         this, context, attrs, defStyleAttr, defStyleRes);
    106                 break;
    107             case MODE_MATERIAL:
    108                 mDelegate = new CalendarViewMaterialDelegate(
    109                         this, context, attrs, defStyleAttr, defStyleRes);
    110                 break;
    111             default:
    112                 throw new IllegalArgumentException("invalid calendarViewMode attribute");
    113         }
    114     }
    115 
    116     /**
    117      * Sets the number of weeks to be shown.
    118      *
    119      * @param count The shown week count.
    120      *
    121      * @attr ref android.R.styleable#CalendarView_shownWeekCount
    122      */
    123     public void setShownWeekCount(int count) {
    124         mDelegate.setShownWeekCount(count);
    125     }
    126 
    127     /**
    128      * Gets the number of weeks to be shown.
    129      *
    130      * @return The shown week count.
    131      *
    132      * @attr ref android.R.styleable#CalendarView_shownWeekCount
    133      */
    134     public int getShownWeekCount() {
    135         return mDelegate.getShownWeekCount();
    136     }
    137 
    138     /**
    139      * Sets the background color for the selected week.
    140      *
    141      * @param color The week background color.
    142      *
    143      * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor
    144      */
    145     public void setSelectedWeekBackgroundColor(int color) {
    146         mDelegate.setSelectedWeekBackgroundColor(color);
    147     }
    148 
    149     /**
    150      * Gets the background color for the selected week.
    151      *
    152      * @return The week background color.
    153      *
    154      * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor
    155      */
    156     public int getSelectedWeekBackgroundColor() {
    157         return mDelegate.getSelectedWeekBackgroundColor();
    158     }
    159 
    160     /**
    161      * Sets the color for the dates of the focused month.
    162      *
    163      * @param color The focused month date color.
    164      *
    165      * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor
    166      */
    167     public void setFocusedMonthDateColor(int color) {
    168         mDelegate.setFocusedMonthDateColor(color);
    169     }
    170 
    171     /**
    172      * Gets the color for the dates in the focused month.
    173      *
    174      * @return The focused month date color.
    175      *
    176      * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor
    177      */
    178     public int getFocusedMonthDateColor() {
    179         return mDelegate.getFocusedMonthDateColor();
    180     }
    181 
    182     /**
    183      * Sets the color for the dates of a not focused month.
    184      *
    185      * @param color A not focused month date color.
    186      *
    187      * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor
    188      */
    189     public void setUnfocusedMonthDateColor(int color) {
    190         mDelegate.setUnfocusedMonthDateColor(color);
    191     }
    192 
    193     /**
    194      * Gets the color for the dates in a not focused month.
    195      *
    196      * @return A not focused month date color.
    197      *
    198      * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor
    199      */
    200     public int getUnfocusedMonthDateColor() {
    201         return mDelegate.getUnfocusedMonthDateColor();
    202     }
    203 
    204     /**
    205      * Sets the color for the week numbers.
    206      *
    207      * @param color The week number color.
    208      *
    209      * @attr ref android.R.styleable#CalendarView_weekNumberColor
    210      */
    211     public void setWeekNumberColor(int color) {
    212         mDelegate.setWeekNumberColor(color);
    213     }
    214 
    215     /**
    216      * Gets the color for the week numbers.
    217      *
    218      * @return The week number color.
    219      *
    220      * @attr ref android.R.styleable#CalendarView_weekNumberColor
    221      */
    222     public int getWeekNumberColor() {
    223         return mDelegate.getWeekNumberColor();
    224     }
    225 
    226     /**
    227      * Sets the color for the separator line between weeks.
    228      *
    229      * @param color The week separator color.
    230      *
    231      * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor
    232      */
    233     public void setWeekSeparatorLineColor(int color) {
    234         mDelegate.setWeekSeparatorLineColor(color);
    235     }
    236 
    237     /**
    238      * Gets the color for the separator line between weeks.
    239      *
    240      * @return The week separator color.
    241      *
    242      * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor
    243      */
    244     public int getWeekSeparatorLineColor() {
    245         return mDelegate.getWeekSeparatorLineColor();
    246     }
    247 
    248     /**
    249      * Sets the drawable for the vertical bar shown at the beginning and at
    250      * the end of the selected date.
    251      *
    252      * @param resourceId The vertical bar drawable resource id.
    253      *
    254      * @attr ref android.R.styleable#CalendarView_selectedDateVerticalBar
    255      */
    256     public void setSelectedDateVerticalBar(int resourceId) {
    257         mDelegate.setSelectedDateVerticalBar(resourceId);
    258     }
    259 
    260     /**
    261      * Sets the drawable for the vertical bar shown at the beginning and at
    262      * the end of the selected date.
    263      *
    264      * @param drawable The vertical bar drawable.
    265      *
    266      * @attr ref android.R.styleable#CalendarView_selectedDateVerticalBar
    267      */
    268     public void setSelectedDateVerticalBar(Drawable drawable) {
    269         mDelegate.setSelectedDateVerticalBar(drawable);
    270     }
    271 
    272     /**
    273      * Gets the drawable for the vertical bar shown at the beginning and at
    274      * the end of the selected date.
    275      *
    276      * @return The vertical bar drawable.
    277      */
    278     public Drawable getSelectedDateVerticalBar() {
    279         return mDelegate.getSelectedDateVerticalBar();
    280     }
    281 
    282     /**
    283      * Sets the text appearance for the week day abbreviation of the calendar header.
    284      *
    285      * @param resourceId The text appearance resource id.
    286      *
    287      * @attr ref android.R.styleable#CalendarView_weekDayTextAppearance
    288      */
    289     public void setWeekDayTextAppearance(int resourceId) {
    290         mDelegate.setWeekDayTextAppearance(resourceId);
    291     }
    292 
    293     /**
    294      * Gets the text appearance for the week day abbreviation of the calendar header.
    295      *
    296      * @return The text appearance resource id.
    297      *
    298      * @attr ref android.R.styleable#CalendarView_weekDayTextAppearance
    299      */
    300     public int getWeekDayTextAppearance() {
    301         return mDelegate.getWeekDayTextAppearance();
    302     }
    303 
    304     /**
    305      * Sets the text appearance for the calendar dates.
    306      *
    307      * @param resourceId The text appearance resource id.
    308      *
    309      * @attr ref android.R.styleable#CalendarView_dateTextAppearance
    310      */
    311     public void setDateTextAppearance(int resourceId) {
    312         mDelegate.setDateTextAppearance(resourceId);
    313     }
    314 
    315     /**
    316      * Gets the text appearance for the calendar dates.
    317      *
    318      * @return The text appearance resource id.
    319      *
    320      * @attr ref android.R.styleable#CalendarView_dateTextAppearance
    321      */
    322     public int getDateTextAppearance() {
    323         return mDelegate.getDateTextAppearance();
    324     }
    325 
    326     /**
    327      * Gets the minimal date supported by this {@link CalendarView} in milliseconds
    328      * since January 1, 1970 00:00:00 in {@link TimeZone#getDefault()} time
    329      * zone.
    330      * <p>
    331      * Note: The default minimal date is 01/01/1900.
    332      * <p>
    333      *
    334      * @return The minimal supported date.
    335      *
    336      * @attr ref android.R.styleable#CalendarView_minDate
    337      */
    338     public long getMinDate() {
    339         return mDelegate.getMinDate();
    340     }
    341 
    342     /**
    343      * Sets the minimal date supported by this {@link CalendarView} in milliseconds
    344      * since January 1, 1970 00:00:00 in {@link TimeZone#getDefault()} time
    345      * zone.
    346      *
    347      * @param minDate The minimal supported date.
    348      *
    349      * @attr ref android.R.styleable#CalendarView_minDate
    350      */
    351     public void setMinDate(long minDate) {
    352         mDelegate.setMinDate(minDate);
    353     }
    354 
    355     /**
    356      * Gets the maximal date supported by this {@link CalendarView} in milliseconds
    357      * since January 1, 1970 00:00:00 in {@link TimeZone#getDefault()} time
    358      * zone.
    359      * <p>
    360      * Note: The default maximal date is 01/01/2100.
    361      * <p>
    362      *
    363      * @return The maximal supported date.
    364      *
    365      * @attr ref android.R.styleable#CalendarView_maxDate
    366      */
    367     public long getMaxDate() {
    368         return mDelegate.getMaxDate();
    369     }
    370 
    371     /**
    372      * Sets the maximal date supported by this {@link CalendarView} in milliseconds
    373      * since January 1, 1970 00:00:00 in {@link TimeZone#getDefault()} time
    374      * zone.
    375      *
    376      * @param maxDate The maximal supported date.
    377      *
    378      * @attr ref android.R.styleable#CalendarView_maxDate
    379      */
    380     public void setMaxDate(long maxDate) {
    381         mDelegate.setMaxDate(maxDate);
    382     }
    383 
    384     /**
    385      * Sets whether to show the week number.
    386      *
    387      * @param showWeekNumber True to show the week number.
    388      *
    389      * @attr ref android.R.styleable#CalendarView_showWeekNumber
    390      */
    391     public void setShowWeekNumber(boolean showWeekNumber) {
    392         mDelegate.setShowWeekNumber(showWeekNumber);
    393     }
    394 
    395     /**
    396      * Gets whether to show the week number.
    397      *
    398      * @return True if showing the week number.
    399      *
    400      * @attr ref android.R.styleable#CalendarView_showWeekNumber
    401      */
    402     public boolean getShowWeekNumber() {
    403         return mDelegate.getShowWeekNumber();
    404     }
    405 
    406     /**
    407      * Gets the first day of week.
    408      *
    409      * @return The first day of the week conforming to the {@link CalendarView}
    410      *         APIs.
    411      * @see Calendar#MONDAY
    412      * @see Calendar#TUESDAY
    413      * @see Calendar#WEDNESDAY
    414      * @see Calendar#THURSDAY
    415      * @see Calendar#FRIDAY
    416      * @see Calendar#SATURDAY
    417      * @see Calendar#SUNDAY
    418      *
    419      * @attr ref android.R.styleable#CalendarView_firstDayOfWeek
    420      */
    421     public int getFirstDayOfWeek() {
    422         return mDelegate.getFirstDayOfWeek();
    423     }
    424 
    425     /**
    426      * Sets the first day of week.
    427      *
    428      * @param firstDayOfWeek The first day of the week conforming to the
    429      *            {@link CalendarView} APIs.
    430      * @see Calendar#MONDAY
    431      * @see Calendar#TUESDAY
    432      * @see Calendar#WEDNESDAY
    433      * @see Calendar#THURSDAY
    434      * @see Calendar#FRIDAY
    435      * @see Calendar#SATURDAY
    436      * @see Calendar#SUNDAY
    437      *
    438      * @attr ref android.R.styleable#CalendarView_firstDayOfWeek
    439      */
    440     public void setFirstDayOfWeek(int firstDayOfWeek) {
    441         mDelegate.setFirstDayOfWeek(firstDayOfWeek);
    442     }
    443 
    444     /**
    445      * Sets the listener to be notified upon selected date change.
    446      *
    447      * @param listener The listener to be notified.
    448      */
    449     public void setOnDateChangeListener(OnDateChangeListener listener) {
    450         mDelegate.setOnDateChangeListener(listener);
    451     }
    452 
    453     /**
    454      * Gets the selected date in milliseconds since January 1, 1970 00:00:00 in
    455      * {@link TimeZone#getDefault()} time zone.
    456      *
    457      * @return The selected date.
    458      */
    459     public long getDate() {
    460         return mDelegate.getDate();
    461     }
    462 
    463     /**
    464      * Sets the selected date in milliseconds since January 1, 1970 00:00:00 in
    465      * {@link TimeZone#getDefault()} time zone.
    466      *
    467      * @param date The selected date.
    468      *
    469      * @throws IllegalArgumentException of the provided date is before the
    470      *        minimal or after the maximal date.
    471      *
    472      * @see #setDate(long, boolean, boolean)
    473      * @see #setMinDate(long)
    474      * @see #setMaxDate(long)
    475      */
    476     public void setDate(long date) {
    477         mDelegate.setDate(date);
    478     }
    479 
    480     /**
    481      * Sets the selected date in milliseconds since January 1, 1970 00:00:00 in
    482      * {@link TimeZone#getDefault()} time zone.
    483      *
    484      * @param date The date.
    485      * @param animate Whether to animate the scroll to the current date.
    486      * @param center Whether to center the current date even if it is already visible.
    487      *
    488      * @throws IllegalArgumentException of the provided date is before the
    489      *        minimal or after the maximal date.
    490      *
    491      * @see #setMinDate(long)
    492      * @see #setMaxDate(long)
    493      */
    494     public void setDate(long date, boolean animate, boolean center) {
    495         mDelegate.setDate(date, animate, center);
    496     }
    497 
    498     @Override
    499     protected void onConfigurationChanged(Configuration newConfig) {
    500         super.onConfigurationChanged(newConfig);
    501         mDelegate.onConfigurationChanged(newConfig);
    502     }
    503 
    504     @Override
    505     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
    506         event.setClassName(CalendarView.class.getName());
    507     }
    508 
    509     @Override
    510     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
    511         info.setClassName(CalendarView.class.getName());
    512     }
    513 
    514     /**
    515      * A delegate interface that defined the public API of the CalendarView. Allows different
    516      * CalendarView implementations. This would need to be implemented by the CalendarView delegates
    517      * for the real behavior.
    518      */
    519     private interface CalendarViewDelegate {
    520         void setShownWeekCount(int count);
    521         int getShownWeekCount();
    522 
    523         void setSelectedWeekBackgroundColor(int color);
    524         int getSelectedWeekBackgroundColor();
    525 
    526         void setFocusedMonthDateColor(int color);
    527         int getFocusedMonthDateColor();
    528 
    529         void setUnfocusedMonthDateColor(int color);
    530         int getUnfocusedMonthDateColor();
    531 
    532         void setWeekNumberColor(int color);
    533         int getWeekNumberColor();
    534 
    535         void setWeekSeparatorLineColor(int color);
    536         int getWeekSeparatorLineColor();
    537 
    538         void setSelectedDateVerticalBar(int resourceId);
    539         void setSelectedDateVerticalBar(Drawable drawable);
    540         Drawable getSelectedDateVerticalBar();
    541 
    542         void setWeekDayTextAppearance(int resourceId);
    543         int getWeekDayTextAppearance();
    544 
    545         void setDateTextAppearance(int resourceId);
    546         int getDateTextAppearance();
    547 
    548         void setMinDate(long minDate);
    549         long getMinDate();
    550 
    551         void setMaxDate(long maxDate);
    552         long getMaxDate();
    553 
    554         void setShowWeekNumber(boolean showWeekNumber);
    555         boolean getShowWeekNumber();
    556 
    557         void setFirstDayOfWeek(int firstDayOfWeek);
    558         int getFirstDayOfWeek();
    559 
    560         void setDate(long date);
    561         void setDate(long date, boolean animate, boolean center);
    562         long getDate();
    563 
    564         void setOnDateChangeListener(OnDateChangeListener listener);
    565 
    566         void onConfigurationChanged(Configuration newConfig);
    567     }
    568 
    569     /**
    570      * An abstract class which can be used as a start for CalendarView implementations
    571      */
    572     abstract static class AbstractCalendarViewDelegate implements CalendarViewDelegate {
    573         /** String for parsing dates. */
    574         private static final String DATE_FORMAT = "MM/dd/yyyy";
    575 
    576         /** The default minimal date. */
    577         protected static final String DEFAULT_MIN_DATE = "01/01/1900";
    578 
    579         /** The default maximal date. */
    580         protected static final String DEFAULT_MAX_DATE = "01/01/2100";
    581 
    582         /** Date format for parsing dates. */
    583         protected static final DateFormat DATE_FORMATTER = new SimpleDateFormat(DATE_FORMAT);
    584 
    585         protected CalendarView mDelegator;
    586         protected Context mContext;
    587         protected Locale mCurrentLocale;
    588 
    589         AbstractCalendarViewDelegate(CalendarView delegator, Context context) {
    590             mDelegator = delegator;
    591             mContext = context;
    592 
    593             // Initialization based on locale
    594             setCurrentLocale(Locale.getDefault());
    595         }
    596 
    597         protected void setCurrentLocale(Locale locale) {
    598             if (locale.equals(mCurrentLocale)) {
    599                 return;
    600             }
    601             mCurrentLocale = locale;
    602         }
    603 
    604         /**
    605          * Parses the given <code>date</code> and in case of success sets
    606          * the result to the <code>outDate</code>.
    607          *
    608          * @return True if the date was parsed.
    609          */
    610         protected boolean parseDate(String date, Calendar outDate) {
    611             try {
    612                 outDate.setTime(DATE_FORMATTER.parse(date));
    613                 return true;
    614             } catch (ParseException e) {
    615                 Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT);
    616                 return false;
    617             }
    618         }
    619     }
    620 
    621 }
    622