DayPickerView.java revision 816aa142023c75cf427401c21831193998bdf233
1bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio/*
2bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Copyright (C) 2014 The Android Open Source Project
3bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio *
4bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Licensed under the Apache License, Version 2.0 (the "License");
5bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * you may not use this file except in compliance with the License.
6bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * You may obtain a copy of the License at
7bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio *
8bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio *      http://www.apache.org/licenses/LICENSE-2.0
9bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio *
10bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Unless required by applicable law or agreed to in writing, software
11bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * distributed under the License is distributed on an "AS IS" BASIS,
12bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * See the License for the specific language governing permissions and
14bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * limitations under the License.
15bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */
16bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
17bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Megliopackage android.widget;
18bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
190ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport com.android.internal.widget.ViewPager;
200ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport com.android.internal.R;
210ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
22bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.Context;
23bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.res.ColorStateList;
240ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport android.content.res.TypedArray;
25816aa142023c75cf427401c21831193998bdf233Alan Viveretteimport android.graphics.drawable.Drawable;
260ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport android.util.AttributeSet;
2750eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viveretteimport android.util.MathUtils;
28816aa142023c75cf427401c21831193998bdf233Alan Viveretteimport android.view.View;
29bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
30816aa142023c75cf427401c21831193998bdf233Alan Viveretteimport java.util.ArrayList;
31bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.Calendar;
32bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.Locale;
33bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
340ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport libcore.icu.LocaleData;
350ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
36bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio/**
37bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * This displays a list of months in a calendar format with selectable days.
38bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */
390ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteclass DayPickerView extends ViewPager {
400ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private static final int DEFAULT_START_YEAR = 1900;
410ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private static final int DEFAULT_END_YEAR = 2100;
42bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
430ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private final Calendar mSelectedDay = Calendar.getInstance();
440ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private final Calendar mMinDate = Calendar.getInstance();
450ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private final Calendar mMaxDate = Calendar.getInstance();
46bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
47816aa142023c75cf427401c21831193998bdf233Alan Viverette    private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
48816aa142023c75cf427401c21831193998bdf233Alan Viverette
490ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private final DayPickerAdapter mAdapter;
50bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
510ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    /** Temporary calendar used for date calculations. */
520ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private Calendar mTempCalendar;
53bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
540ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private OnDaySelectedListener mOnDaySelectedListener;
55e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette
560ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    public DayPickerView(Context context) {
570ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        this(context, null);
580ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
59bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
600ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    public DayPickerView(Context context, AttributeSet attrs) {
610ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        this(context, attrs, R.attr.calendarViewStyle);
620ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
63bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
640ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    public DayPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
650ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        this(context, attrs, defStyleAttr, 0);
660ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
6750eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette
680ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    public DayPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
690ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        super(context, attrs, defStyleAttr, defStyleRes);
704612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
710ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final TypedArray a = context.obtainStyledAttributes(attrs,
720ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.styleable.CalendarView, defStyleAttr, defStyleRes);
73bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
740ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int firstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek,
750ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                LocaleData.get(Locale.getDefault()).firstDayOfWeek);
76bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
770ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final String minDate = a.getString(R.styleable.CalendarView_minDate);
780ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final String maxDate = a.getString(R.styleable.CalendarView_maxDate);
79bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
800ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int monthTextAppearanceResId = a.getResourceId(
810ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.styleable.CalendarView_monthTextAppearance,
820ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.style.TextAppearance_Material_Widget_Calendar_Month);
830ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int dayOfWeekTextAppearanceResId = a.getResourceId(
840ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.styleable.CalendarView_weekDayTextAppearance,
850ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.style.TextAppearance_Material_Widget_Calendar_DayOfWeek);
860ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int dayTextAppearanceResId = a.getResourceId(
870ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.styleable.CalendarView_dateTextAppearance,
880ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.style.TextAppearance_Material_Widget_Calendar_Day);
890ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
900ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final ColorStateList daySelectorColor = a.getColorStateList(
910ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.styleable.CalendarView_daySelectorColor);
920ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
930ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        a.recycle();
940ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
950ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Set up adapter.
9660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette        mAdapter = new DayPickerAdapter(context,
9760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette                R.layout.date_picker_month_item_material, R.id.month_view);
980ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mAdapter.setMonthTextAppearance(monthTextAppearanceResId);
990ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mAdapter.setDayOfWeekTextAppearance(dayOfWeekTextAppearanceResId);
1000ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mAdapter.setDayTextAppearance(dayTextAppearanceResId);
1010ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mAdapter.setDaySelectorColor(daySelectorColor);
10250eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette
103bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        setAdapter(mAdapter);
104e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette
1050ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Set up min and max dates.
1060ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final Calendar tempDate = Calendar.getInstance();
1070ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (!CalendarView.parseDate(minDate, tempDate)) {
1080ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            tempDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1);
1090ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
1100ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final long minDateMillis = tempDate.getTimeInMillis();
1110ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1120ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (!CalendarView.parseDate(maxDate, tempDate)) {
1130ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            tempDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31);
1140ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
1150ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final long maxDateMillis = tempDate.getTimeInMillis();
1160ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1170ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (maxDateMillis < minDateMillis) {
1180ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            throw new IllegalArgumentException("maxDate must be >= minDate");
1190ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
1200ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1210ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final long setDateMillis = MathUtils.constrain(
1220ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                System.currentTimeMillis(), minDateMillis, maxDateMillis);
123e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette
1240ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setFirstDayOfWeek(firstDayOfWeek);
1250ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setMinDate(minDateMillis);
1260ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setMaxDate(maxDateMillis);
1270ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setDate(setDateMillis, false);
1280ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1290ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Proxy selection callbacks to our own listener.
1300ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mAdapter.setOnDaySelectedListener(new DayPickerAdapter.OnDaySelectedListener() {
1310ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            @Override
1320ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            public void onDaySelected(DayPickerAdapter adapter, Calendar day) {
1330ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                if (mOnDaySelectedListener != null) {
1340ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                    mOnDaySelectedListener.onDaySelected(DayPickerView.this, day);
1350ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                }
1360ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            }
13760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette
13860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette            @Override
13960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette            public void onNavigationClick(DayPickerAdapter view, int direction, boolean animate) {
14060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette                // ViewPager clamps input values, so we don't need to worry
14160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette                // about passing invalid indices.
14260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette                final int nextItem = getCurrentItem() + direction;
14360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette                setCurrentItem(nextItem, animate);
14460b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette            }
1450ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        });
1460ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
1470ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
148816aa142023c75cf427401c21831193998bdf233Alan Viverette    @Override
149816aa142023c75cf427401c21831193998bdf233Alan Viverette    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
150816aa142023c75cf427401c21831193998bdf233Alan Viverette        populate();
151816aa142023c75cf427401c21831193998bdf233Alan Viverette
152816aa142023c75cf427401c21831193998bdf233Alan Viverette        // Everything below is mostly copied from FrameLayout.
153816aa142023c75cf427401c21831193998bdf233Alan Viverette        int count = getChildCount();
154816aa142023c75cf427401c21831193998bdf233Alan Viverette
155816aa142023c75cf427401c21831193998bdf233Alan Viverette        final boolean measureMatchParentChildren =
156816aa142023c75cf427401c21831193998bdf233Alan Viverette                MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
157816aa142023c75cf427401c21831193998bdf233Alan Viverette                        MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
158816aa142023c75cf427401c21831193998bdf233Alan Viverette
159816aa142023c75cf427401c21831193998bdf233Alan Viverette        int maxHeight = 0;
160816aa142023c75cf427401c21831193998bdf233Alan Viverette        int maxWidth = 0;
161816aa142023c75cf427401c21831193998bdf233Alan Viverette        int childState = 0;
162816aa142023c75cf427401c21831193998bdf233Alan Viverette
163816aa142023c75cf427401c21831193998bdf233Alan Viverette        for (int i = 0; i < count; i++) {
164816aa142023c75cf427401c21831193998bdf233Alan Viverette            final View child = getChildAt(i);
165816aa142023c75cf427401c21831193998bdf233Alan Viverette            if (child.getVisibility() != GONE) {
166816aa142023c75cf427401c21831193998bdf233Alan Viverette                measureChild(child, widthMeasureSpec, heightMeasureSpec);
167816aa142023c75cf427401c21831193998bdf233Alan Viverette                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
168816aa142023c75cf427401c21831193998bdf233Alan Viverette                maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
169816aa142023c75cf427401c21831193998bdf233Alan Viverette                maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
170816aa142023c75cf427401c21831193998bdf233Alan Viverette                childState = combineMeasuredStates(childState, child.getMeasuredState());
171816aa142023c75cf427401c21831193998bdf233Alan Viverette                if (measureMatchParentChildren) {
172816aa142023c75cf427401c21831193998bdf233Alan Viverette                    if (lp.width == LayoutParams.MATCH_PARENT ||
173816aa142023c75cf427401c21831193998bdf233Alan Viverette                            lp.height == LayoutParams.MATCH_PARENT) {
174816aa142023c75cf427401c21831193998bdf233Alan Viverette                        mMatchParentChildren.add(child);
175816aa142023c75cf427401c21831193998bdf233Alan Viverette                    }
176816aa142023c75cf427401c21831193998bdf233Alan Viverette                }
177816aa142023c75cf427401c21831193998bdf233Alan Viverette            }
178816aa142023c75cf427401c21831193998bdf233Alan Viverette        }
179816aa142023c75cf427401c21831193998bdf233Alan Viverette
180816aa142023c75cf427401c21831193998bdf233Alan Viverette        // Account for padding too
181816aa142023c75cf427401c21831193998bdf233Alan Viverette        maxWidth += getPaddingLeft() + getPaddingRight();
182816aa142023c75cf427401c21831193998bdf233Alan Viverette        maxHeight += getPaddingTop() + getPaddingBottom();
183816aa142023c75cf427401c21831193998bdf233Alan Viverette
184816aa142023c75cf427401c21831193998bdf233Alan Viverette        // Check against our minimum height and width
185816aa142023c75cf427401c21831193998bdf233Alan Viverette        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
186816aa142023c75cf427401c21831193998bdf233Alan Viverette        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
187816aa142023c75cf427401c21831193998bdf233Alan Viverette
188816aa142023c75cf427401c21831193998bdf233Alan Viverette        // Check against our foreground's minimum height and width
189816aa142023c75cf427401c21831193998bdf233Alan Viverette        final Drawable drawable = getForeground();
190816aa142023c75cf427401c21831193998bdf233Alan Viverette        if (drawable != null) {
191816aa142023c75cf427401c21831193998bdf233Alan Viverette            maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
192816aa142023c75cf427401c21831193998bdf233Alan Viverette            maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
193816aa142023c75cf427401c21831193998bdf233Alan Viverette        }
194816aa142023c75cf427401c21831193998bdf233Alan Viverette
195816aa142023c75cf427401c21831193998bdf233Alan Viverette        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
196816aa142023c75cf427401c21831193998bdf233Alan Viverette                resolveSizeAndState(maxHeight, heightMeasureSpec,
197816aa142023c75cf427401c21831193998bdf233Alan Viverette                        childState << MEASURED_HEIGHT_STATE_SHIFT));
198816aa142023c75cf427401c21831193998bdf233Alan Viverette
199816aa142023c75cf427401c21831193998bdf233Alan Viverette        count = mMatchParentChildren.size();
200816aa142023c75cf427401c21831193998bdf233Alan Viverette        if (count > 1) {
201816aa142023c75cf427401c21831193998bdf233Alan Viverette            for (int i = 0; i < count; i++) {
202816aa142023c75cf427401c21831193998bdf233Alan Viverette                final View child = mMatchParentChildren.get(i);
203816aa142023c75cf427401c21831193998bdf233Alan Viverette
204816aa142023c75cf427401c21831193998bdf233Alan Viverette                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
205816aa142023c75cf427401c21831193998bdf233Alan Viverette                final int childWidthMeasureSpec;
206816aa142023c75cf427401c21831193998bdf233Alan Viverette                final int childHeightMeasureSpec;
207816aa142023c75cf427401c21831193998bdf233Alan Viverette
208816aa142023c75cf427401c21831193998bdf233Alan Viverette                if (lp.width == LayoutParams.MATCH_PARENT) {
209816aa142023c75cf427401c21831193998bdf233Alan Viverette                    childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
210816aa142023c75cf427401c21831193998bdf233Alan Viverette                            getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
211816aa142023c75cf427401c21831193998bdf233Alan Viverette                            MeasureSpec.EXACTLY);
212816aa142023c75cf427401c21831193998bdf233Alan Viverette                } else {
213816aa142023c75cf427401c21831193998bdf233Alan Viverette                    childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
214816aa142023c75cf427401c21831193998bdf233Alan Viverette                            getPaddingLeft() + getPaddingRight(),
215816aa142023c75cf427401c21831193998bdf233Alan Viverette                            lp.width);
216816aa142023c75cf427401c21831193998bdf233Alan Viverette                }
217816aa142023c75cf427401c21831193998bdf233Alan Viverette
218816aa142023c75cf427401c21831193998bdf233Alan Viverette                if (lp.height == LayoutParams.MATCH_PARENT) {
219816aa142023c75cf427401c21831193998bdf233Alan Viverette                    childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
220816aa142023c75cf427401c21831193998bdf233Alan Viverette                            getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
221816aa142023c75cf427401c21831193998bdf233Alan Viverette                            MeasureSpec.EXACTLY);
222816aa142023c75cf427401c21831193998bdf233Alan Viverette                } else {
223816aa142023c75cf427401c21831193998bdf233Alan Viverette                    childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
224816aa142023c75cf427401c21831193998bdf233Alan Viverette                            getPaddingTop() + getPaddingBottom(),
225816aa142023c75cf427401c21831193998bdf233Alan Viverette                            lp.height);
226816aa142023c75cf427401c21831193998bdf233Alan Viverette                }
227816aa142023c75cf427401c21831193998bdf233Alan Viverette
228816aa142023c75cf427401c21831193998bdf233Alan Viverette                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
229816aa142023c75cf427401c21831193998bdf233Alan Viverette            }
230816aa142023c75cf427401c21831193998bdf233Alan Viverette        }
231816aa142023c75cf427401c21831193998bdf233Alan Viverette
232816aa142023c75cf427401c21831193998bdf233Alan Viverette        mMatchParentChildren.clear();
233816aa142023c75cf427401c21831193998bdf233Alan Viverette    }
234816aa142023c75cf427401c21831193998bdf233Alan Viverette
2350ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    public void setDayOfWeekTextAppearance(int resId) {
2360ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mAdapter.setDayOfWeekTextAppearance(resId);
2370ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
2380ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2390ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    public int getDayOfWeekTextAppearance() {
2400ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        return mAdapter.getDayOfWeekTextAppearance();
2410ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
2420ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2430ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    public void setDayTextAppearance(int resId) {
2440ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mAdapter.setDayTextAppearance(resId);
2450ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
2460ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2470ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    public int getDayTextAppearance() {
2480ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        return mAdapter.getDayTextAppearance();
249e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette    }
250e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette
2514612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    /**
2524612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette     * Sets the currently selected date to the specified timestamp. Jumps
2534612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette     * immediately to the new date. To animate to the new date, use
2540ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * {@link #setDate(long, boolean)}.
2554612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette     *
2560ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * @param timeInMillis the target day in milliseconds
2574612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette     */
2584612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public void setDate(long timeInMillis) {
2590ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setDate(timeInMillis, false);
2604612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
2614612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
2620ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    /**
2630ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * Sets the currently selected date to the specified timestamp. Jumps
2640ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * immediately to the new date, optionally animating the transition.
2650ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     *
2660ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * @param timeInMillis the target day in milliseconds
2670ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * @param animate whether to smooth scroll to the new position
2680ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     */
2690ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    public void setDate(long timeInMillis, boolean animate) {
2700ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setDate(timeInMillis, animate, true);
2710ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
2720ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2730ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    /**
2740ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * Moves to the month containing the specified day, optionally setting the
2750ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * day as selected.
2760ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     *
2770ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * @param timeInMillis the target day in milliseconds
2780ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * @param animate whether to smooth scroll to the new position
2790ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * @param setSelected whether to set the specified day as selected
2800ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     */
2810ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private void setDate(long timeInMillis, boolean animate, boolean setSelected) {
2820ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (setSelected) {
2830ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            mSelectedDay.setTimeInMillis(timeInMillis);
2840ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
2850ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2860ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int position = getPositionFromDay(timeInMillis);
2870ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (position != getCurrentItem()) {
2880ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            setCurrentItem(position, animate);
2890ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
290f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette
291f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette        mTempCalendar.setTimeInMillis(timeInMillis);
292f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette        mAdapter.setSelectedDay(mTempCalendar);
2934612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
2944612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
2954612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public long getDate() {
2964612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        return mSelectedDay.getTimeInMillis();
297e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette    }
298e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette
299e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette    public void setFirstDayOfWeek(int firstDayOfWeek) {
300e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette        mAdapter.setFirstDayOfWeek(firstDayOfWeek);
301bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
302bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
3034612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public int getFirstDayOfWeek() {
3044612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        return mAdapter.getFirstDayOfWeek();
3054612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
3064612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
3074612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public void setMinDate(long timeInMillis) {
3084612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        mMinDate.setTimeInMillis(timeInMillis);
3094612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        onRangeChanged();
3104612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
3114612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
3124612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public long getMinDate() {
3134612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        return mMinDate.getTimeInMillis();
3144612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
3154612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
3164612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public void setMaxDate(long timeInMillis) {
3174612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        mMaxDate.setTimeInMillis(timeInMillis);
3184612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        onRangeChanged();
3194612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
32050eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette
3214612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public long getMaxDate() {
3224612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        return mMaxDate.getTimeInMillis();
3234612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
3244612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
3254612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    /**
3264612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette     * Handles changes to date range.
3274612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette     */
3284612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public void onRangeChanged() {
32950eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette        mAdapter.setRange(mMinDate, mMaxDate);
33050eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette
3315ecbfeb38b6bdcfe8f3561f8cdcb4af9ba30c886Alan Viverette        // Changing the min/max date changes the selection position since we
3324612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        // don't really have stable IDs. Jumps immediately to the new position.
3330ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setDate(mSelectedDay.getTimeInMillis(), false, false);
33450eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette    }
33550eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette
33650eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette    /**
337e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette     * Sets the listener to call when the user selects a day.
33850eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette     *
339e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette     * @param listener The listener to call.
340bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio     */
341e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette    public void setOnDaySelectedListener(OnDaySelectedListener listener) {
342e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette        mOnDaySelectedListener = listener;
343bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
344bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
34550eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette    private int getDiffMonths(Calendar start, Calendar end) {
346bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        final int diffYears = end.get(Calendar.YEAR) - start.get(Calendar.YEAR);
3470ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        return end.get(Calendar.MONTH) - start.get(Calendar.MONTH) + 12 * diffYears;
348bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
349bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
3504612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    private int getPositionFromDay(long timeInMillis) {
35150eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette        final int diffMonthMax = getDiffMonths(mMinDate, mMaxDate);
3524612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        final int diffMonth = getDiffMonths(mMinDate, getTempCalendarForTime(timeInMillis));
35350eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette        return MathUtils.constrain(diffMonth, 0, diffMonthMax);
354bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
355bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
3564612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    private Calendar getTempCalendarForTime(long timeInMillis) {
3574612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        if (mTempCalendar == null) {
3584612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette            mTempCalendar = Calendar.getInstance();
3594612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        }
3604612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        mTempCalendar.setTimeInMillis(timeInMillis);
3614612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        return mTempCalendar;
3624612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
3634612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
364bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    /**
365bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio     * Gets the position of the view that is most prominently displayed within the list view.
366bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio     */
367bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public int getMostVisiblePosition() {
3680ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        return getCurrentItem();
369bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
370e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette
371e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette    public interface OnDaySelectedListener {
372e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette        public void onDaySelected(DayPickerView view, Calendar day);
373e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette    }
374bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio}
375