CalendarView.java revision 4612740ddc76b3518dc6d189d5f8b5b7f60e9d64
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
17package android.widget;
18
19import android.annotation.Widget;
20import android.content.Context;
21import android.content.res.Configuration;
22import android.content.res.TypedArray;
23import android.graphics.drawable.Drawable;
24import android.util.AttributeSet;
25import android.util.Log;
26import android.view.accessibility.AccessibilityEvent;
27import android.view.accessibility.AccessibilityNodeInfo;
28
29import com.android.internal.R;
30
31import java.text.DateFormat;
32import java.text.ParseException;
33import java.text.SimpleDateFormat;
34import java.util.Calendar;
35import java.util.Locale;
36import 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
58public 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