1bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio/*
278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * Copyright (C) 2015 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.R;
2078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viveretteimport com.android.internal.widget.ViewPager;
2178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viveretteimport com.android.internal.widget.ViewPager.OnPageChangeListener;
220ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viveretteimport android.annotation.Nullable;
24bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.Context;
25bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.res.ColorStateList;
260ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport android.content.res.TypedArray;
2768763be41cffbcb4883a0a6293fc1aa9e17a3957Alan Viveretteimport android.icu.util.Calendar;
280ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport android.util.AttributeSet;
2950eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viveretteimport android.util.MathUtils;
3078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viveretteimport android.view.LayoutInflater;
31816aa142023c75cf427401c21831193998bdf233Alan Viveretteimport android.view.View;
3278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viveretteimport android.view.ViewGroup;
3378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viveretteimport android.view.accessibility.AccessibilityManager;
34bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
35bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.Locale;
36bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
370ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport libcore.icu.LocaleData;
380ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
3978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viveretteclass DayPickerView extends ViewGroup {
4078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    private static final int DEFAULT_LAYOUT = R.layout.day_picker_content_material;
410ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private static final int DEFAULT_START_YEAR = 1900;
420ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private static final int DEFAULT_END_YEAR = 2100;
43bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
4478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    private static final int[] ATTRS_TEXT_COLOR = new int[] { R.attr.textColor };
4578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
460ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private final Calendar mSelectedDay = Calendar.getInstance();
470ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private final Calendar mMinDate = Calendar.getInstance();
480ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private final Calendar mMaxDate = Calendar.getInstance();
49bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
5078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    private final AccessibilityManager mAccessibilityManager;
5178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
5278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    private final ViewPager mViewPager;
5378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    private final ImageButton mPrevButton;
5478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    private final ImageButton mNextButton;
55816aa142023c75cf427401c21831193998bdf233Alan Viverette
5678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    private final DayPickerPagerAdapter mAdapter;
57bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
580ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    /** Temporary calendar used for date calculations. */
590ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private Calendar mTempCalendar;
60bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
610ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private OnDaySelectedListener mOnDaySelectedListener;
62e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette
630ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    public DayPickerView(Context context) {
640ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        this(context, null);
650ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
66bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
6778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    public DayPickerView(Context context, @Nullable AttributeSet attrs) {
680ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        this(context, attrs, R.attr.calendarViewStyle);
690ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
70bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
7178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    public DayPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
720ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        this(context, attrs, defStyleAttr, 0);
730ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
7450eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette
7578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    public DayPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
7678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            int defStyleRes) {
770ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        super(context, attrs, defStyleAttr, defStyleRes);
784612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
7978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        mAccessibilityManager = (AccessibilityManager) context.getSystemService(
8078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette                Context.ACCESSIBILITY_SERVICE);
8178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
820ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final TypedArray a = context.obtainStyledAttributes(attrs,
830ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.styleable.CalendarView, defStyleAttr, defStyleRes);
84bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
850ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int firstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek,
860ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                LocaleData.get(Locale.getDefault()).firstDayOfWeek);
87bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
880ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final String minDate = a.getString(R.styleable.CalendarView_minDate);
890ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final String maxDate = a.getString(R.styleable.CalendarView_maxDate);
90bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
910ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int monthTextAppearanceResId = a.getResourceId(
920ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.styleable.CalendarView_monthTextAppearance,
930ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.style.TextAppearance_Material_Widget_Calendar_Month);
940ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int dayOfWeekTextAppearanceResId = a.getResourceId(
950ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.styleable.CalendarView_weekDayTextAppearance,
960ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.style.TextAppearance_Material_Widget_Calendar_DayOfWeek);
970ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int dayTextAppearanceResId = a.getResourceId(
980ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.styleable.CalendarView_dateTextAppearance,
990ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.style.TextAppearance_Material_Widget_Calendar_Day);
1000ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1010ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final ColorStateList daySelectorColor = a.getColorStateList(
1020ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.styleable.CalendarView_daySelectorColor);
1030ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1040ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        a.recycle();
1050ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1060ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Set up adapter.
10778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        mAdapter = new DayPickerPagerAdapter(context,
10860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette                R.layout.date_picker_month_item_material, R.id.month_view);
1090ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mAdapter.setMonthTextAppearance(monthTextAppearanceResId);
1100ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mAdapter.setDayOfWeekTextAppearance(dayOfWeekTextAppearanceResId);
1110ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mAdapter.setDayTextAppearance(dayTextAppearanceResId);
1120ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mAdapter.setDaySelectorColor(daySelectorColor);
11350eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette
11478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final LayoutInflater inflater = LayoutInflater.from(context);
11578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final ViewGroup content = (ViewGroup) inflater.inflate(DEFAULT_LAYOUT, this, false);
11678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
11778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        // Transfer all children from content to here.
11878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        while (content.getChildCount() > 0) {
11978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            final View child = content.getChildAt(0);
12078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            content.removeViewAt(0);
12178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            addView(child);
12278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        }
12378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
12478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        mPrevButton = (ImageButton) findViewById(R.id.prev);
12578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        mPrevButton.setOnClickListener(mOnClickListener);
12678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
12778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        mNextButton = (ImageButton) findViewById(R.id.next);
12878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        mNextButton.setOnClickListener(mOnClickListener);
12978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
13078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        mViewPager = (ViewPager) findViewById(R.id.day_picker_view_pager);
13178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        mViewPager.setAdapter(mAdapter);
13278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        mViewPager.setOnPageChangeListener(mOnPageChangedListener);
13378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
13478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        // Proxy the month text color into the previous and next buttons.
13578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        if (monthTextAppearanceResId != 0) {
13678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            final TypedArray ta = mContext.obtainStyledAttributes(null,
13778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette                    ATTRS_TEXT_COLOR, 0, monthTextAppearanceResId);
13878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            final ColorStateList monthColor = ta.getColorStateList(0);
13978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            if (monthColor != null) {
14078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette                mPrevButton.setImageTintList(monthColor);
14178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette                mNextButton.setImageTintList(monthColor);
14278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            }
14378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            ta.recycle();
14478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        }
145e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette
1460ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Set up min and max dates.
1470ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final Calendar tempDate = Calendar.getInstance();
1480ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (!CalendarView.parseDate(minDate, tempDate)) {
1490ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            tempDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1);
1500ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
1510ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final long minDateMillis = tempDate.getTimeInMillis();
1520ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1530ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (!CalendarView.parseDate(maxDate, tempDate)) {
1540ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            tempDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31);
1550ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
1560ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final long maxDateMillis = tempDate.getTimeInMillis();
1570ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1580ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (maxDateMillis < minDateMillis) {
1590ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            throw new IllegalArgumentException("maxDate must be >= minDate");
1600ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
1610ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1620ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final long setDateMillis = MathUtils.constrain(
1630ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                System.currentTimeMillis(), minDateMillis, maxDateMillis);
164e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette
1650ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setFirstDayOfWeek(firstDayOfWeek);
1660ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setMinDate(minDateMillis);
1670ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setMaxDate(maxDateMillis);
1680ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setDate(setDateMillis, false);
1690ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1700ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Proxy selection callbacks to our own listener.
17178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        mAdapter.setOnDaySelectedListener(new DayPickerPagerAdapter.OnDaySelectedListener() {
1720ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            @Override
17378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            public void onDaySelected(DayPickerPagerAdapter adapter, Calendar day) {
1740ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                if (mOnDaySelectedListener != null) {
1750ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                    mOnDaySelectedListener.onDaySelected(DayPickerView.this, day);
1760ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                }
1770ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            }
1780ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        });
1790ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
1800ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1815c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette    private void updateButtonVisibility(int position) {
1825c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette        final boolean hasPrev = position > 0;
1835c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette        final boolean hasNext = position < (mAdapter.getCount() - 1);
1845c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette        mPrevButton.setVisibility(hasPrev ? View.VISIBLE : View.INVISIBLE);
1855c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette        mNextButton.setVisibility(hasNext ? View.VISIBLE : View.INVISIBLE);
1865c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette    }
1875c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette
188816aa142023c75cf427401c21831193998bdf233Alan Viverette    @Override
189816aa142023c75cf427401c21831193998bdf233Alan Viverette    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
19078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final ViewPager viewPager = mViewPager;
19178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        measureChild(viewPager, widthMeasureSpec, heightMeasureSpec);
19278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
19378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int measuredWidthAndState = viewPager.getMeasuredWidthAndState();
19478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int measuredHeightAndState = viewPager.getMeasuredHeightAndState();
19578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        setMeasuredDimension(measuredWidthAndState, measuredHeightAndState);
19678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
19778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int pagerWidth = viewPager.getMeasuredWidth();
19878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int pagerHeight = viewPager.getMeasuredHeight();
19978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int buttonWidthSpec = MeasureSpec.makeMeasureSpec(pagerWidth, MeasureSpec.AT_MOST);
20078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int buttonHeightSpec = MeasureSpec.makeMeasureSpec(pagerHeight, MeasureSpec.AT_MOST);
20178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        mPrevButton.measure(buttonWidthSpec, buttonHeightSpec);
20278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        mNextButton.measure(buttonWidthSpec, buttonHeightSpec);
20378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    }
204816aa142023c75cf427401c21831193998bdf233Alan Viverette
20578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    @Override
206ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette    public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) {
207ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette        super.onRtlPropertiesChanged(layoutDirection);
208ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette
209ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette        requestLayout();
210ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette    }
211ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette
212ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette    @Override
21378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
214ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette        final ImageButton leftButton;
215ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette        final ImageButton rightButton;
216ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette        if (isLayoutRtl()) {
217ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette            leftButton = mNextButton;
218ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette            rightButton = mPrevButton;
219ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette        } else {
220ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette            leftButton = mPrevButton;
221ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette            rightButton = mNextButton;
222ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette        }
22378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
22478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int width = right - left;
22578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int height = bottom - top;
22678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        mViewPager.layout(0, 0, width, height);
22778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
22878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final SimpleMonthView monthView = (SimpleMonthView) mViewPager.getChildAt(0);
22978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int monthHeight = monthView.getMonthHeight();
23078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int cellWidth = monthView.getCellWidth();
23178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
23278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        // Vertically center the previous/next buttons within the month
23378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        // header, horizontally center within the day cell.
23478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int leftDW = leftButton.getMeasuredWidth();
23578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int leftDH = leftButton.getMeasuredHeight();
23678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int leftIconTop = monthView.getPaddingTop() + (monthHeight - leftDH) / 2;
23778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int leftIconLeft = monthView.getPaddingLeft() + (cellWidth - leftDW) / 2;
23878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        leftButton.layout(leftIconLeft, leftIconTop, leftIconLeft + leftDW, leftIconTop + leftDH);
23978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
24078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int rightDW = rightButton.getMeasuredWidth();
24178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int rightDH = rightButton.getMeasuredHeight();
24278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int rightIconTop = monthView.getPaddingTop() + (monthHeight - rightDH) / 2;
24378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        final int rightIconRight = width - monthView.getPaddingRight() - (cellWidth - rightDW) / 2;
24478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        rightButton.layout(rightIconRight - rightDW, rightIconTop,
24578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette                rightIconRight, rightIconTop + rightDH);
246816aa142023c75cf427401c21831193998bdf233Alan Viverette    }
247816aa142023c75cf427401c21831193998bdf233Alan Viverette
2480ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    public void setDayOfWeekTextAppearance(int resId) {
2490ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mAdapter.setDayOfWeekTextAppearance(resId);
2500ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
2510ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2520ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    public int getDayOfWeekTextAppearance() {
2530ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        return mAdapter.getDayOfWeekTextAppearance();
2540ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
2550ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2560ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    public void setDayTextAppearance(int resId) {
2570ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mAdapter.setDayTextAppearance(resId);
2580ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
2590ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2600ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    public int getDayTextAppearance() {
2610ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        return mAdapter.getDayTextAppearance();
262e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette    }
263e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette
2644612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    /**
2654612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette     * Sets the currently selected date to the specified timestamp. Jumps
2664612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette     * immediately to the new date. To animate to the new date, use
2670ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * {@link #setDate(long, boolean)}.
2684612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette     *
2690ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * @param timeInMillis the target day in milliseconds
2704612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette     */
2714612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public void setDate(long timeInMillis) {
2720ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setDate(timeInMillis, false);
2734612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
2744612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
2750ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    /**
2760ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * Sets the currently selected date to the specified timestamp. Jumps
2770ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * immediately to the new date, optionally animating the transition.
2780ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     *
2790ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * @param timeInMillis the target day in milliseconds
2800ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * @param animate whether to smooth scroll to the new position
2810ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     */
2820ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    public void setDate(long timeInMillis, boolean animate) {
2830ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setDate(timeInMillis, animate, true);
2840ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
2850ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2860ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    /**
2870ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * Moves to the month containing the specified day, optionally setting the
2880ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * day as selected.
2890ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     *
2900ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * @param timeInMillis the target day in milliseconds
2910ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * @param animate whether to smooth scroll to the new position
2920ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * @param setSelected whether to set the specified day as selected
2930ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     */
2940ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private void setDate(long timeInMillis, boolean animate, boolean setSelected) {
2950ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (setSelected) {
2960ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            mSelectedDay.setTimeInMillis(timeInMillis);
2970ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
2980ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2990ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int position = getPositionFromDay(timeInMillis);
30078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        if (position != mViewPager.getCurrentItem()) {
30178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            mViewPager.setCurrentItem(position, animate);
3020ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
303f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette
304f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette        mTempCalendar.setTimeInMillis(timeInMillis);
305f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette        mAdapter.setSelectedDay(mTempCalendar);
3064612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
3074612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
3084612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public long getDate() {
3094612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        return mSelectedDay.getTimeInMillis();
310e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette    }
311e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette
312e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette    public void setFirstDayOfWeek(int firstDayOfWeek) {
313e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette        mAdapter.setFirstDayOfWeek(firstDayOfWeek);
314bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
315bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
3164612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public int getFirstDayOfWeek() {
3174612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        return mAdapter.getFirstDayOfWeek();
3184612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
3194612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
3204612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public void setMinDate(long timeInMillis) {
3214612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        mMinDate.setTimeInMillis(timeInMillis);
3224612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        onRangeChanged();
3234612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
3244612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
3254612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public long getMinDate() {
3264612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        return mMinDate.getTimeInMillis();
3274612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
3284612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
3294612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public void setMaxDate(long timeInMillis) {
3304612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        mMaxDate.setTimeInMillis(timeInMillis);
3314612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        onRangeChanged();
3324612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
33350eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette
3344612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public long getMaxDate() {
3354612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        return mMaxDate.getTimeInMillis();
3364612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
3374612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
3384612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    /**
3394612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette     * Handles changes to date range.
3404612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette     */
3414612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    public void onRangeChanged() {
34250eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette        mAdapter.setRange(mMinDate, mMaxDate);
34350eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette
3445ecbfeb38b6bdcfe8f3561f8cdcb4af9ba30c886Alan Viverette        // Changing the min/max date changes the selection position since we
3454612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        // don't really have stable IDs. Jumps immediately to the new position.
3460ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setDate(mSelectedDay.getTimeInMillis(), false, false);
347bd51b4d0b930f8c64920954f4f9e5033e0001d5eAlan Viverette
348bd51b4d0b930f8c64920954f4f9e5033e0001d5eAlan Viverette        updateButtonVisibility(mViewPager.getCurrentItem());
34950eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette    }
35050eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette
35150eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette    /**
352e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette     * Sets the listener to call when the user selects a day.
35350eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette     *
354e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette     * @param listener The listener to call.
355bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio     */
356e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette    public void setOnDaySelectedListener(OnDaySelectedListener listener) {
357e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette        mOnDaySelectedListener = listener;
358bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
359bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
36050eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette    private int getDiffMonths(Calendar start, Calendar end) {
361bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        final int diffYears = end.get(Calendar.YEAR) - start.get(Calendar.YEAR);
3620ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        return end.get(Calendar.MONTH) - start.get(Calendar.MONTH) + 12 * diffYears;
363bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
364bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
3654612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    private int getPositionFromDay(long timeInMillis) {
36650eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette        final int diffMonthMax = getDiffMonths(mMinDate, mMaxDate);
3674612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        final int diffMonth = getDiffMonths(mMinDate, getTempCalendarForTime(timeInMillis));
36850eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette        return MathUtils.constrain(diffMonth, 0, diffMonthMax);
369bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
370bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
3714612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    private Calendar getTempCalendarForTime(long timeInMillis) {
3724612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        if (mTempCalendar == null) {
3734612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette            mTempCalendar = Calendar.getInstance();
3744612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        }
3754612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        mTempCalendar.setTimeInMillis(timeInMillis);
3764612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        return mTempCalendar;
3774612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette    }
3784612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette
379bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    /**
380bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio     * Gets the position of the view that is most prominently displayed within the list view.
381bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio     */
382bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public int getMostVisiblePosition() {
38378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        return mViewPager.getCurrentItem();
384bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
385e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette
38678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    public void setPosition(int position) {
38778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        mViewPager.setCurrentItem(position, false);
38878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    }
38978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
39078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    private final OnPageChangeListener mOnPageChangedListener = new OnPageChangeListener() {
39178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        @Override
39278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
39378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            final float alpha = Math.abs(0.5f - positionOffset) * 2.0f;
39478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            mPrevButton.setAlpha(alpha);
39578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            mNextButton.setAlpha(alpha);
39678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        }
39778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
39878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        @Override
39978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        public void onPageScrollStateChanged(int state) {}
40078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
40178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        @Override
40278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        public void onPageSelected(int position) {
4035c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette            updateButtonVisibility(position);
40478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        }
40578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    };
40678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
40778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    private final OnClickListener mOnClickListener = new OnClickListener() {
40878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        @Override
40978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        public void onClick(View v) {
41078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            final int direction;
41178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            if (v == mPrevButton) {
41278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette                direction = -1;
41378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            } else if (v == mNextButton) {
41478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette                direction = 1;
41578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            } else {
41678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette                return;
41778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            }
41878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
41978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            // Animation is expensive for accessibility services since it sends
42078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            // lots of scroll and content change events.
42178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            final boolean animate = !mAccessibilityManager.isEnabled();
42278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
42378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            // ViewPager clamps input values, so we don't need to worry
42478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            // about passing invalid indices.
42578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            final int nextItem = mViewPager.getCurrentItem() + direction;
42678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette            mViewPager.setCurrentItem(nextItem, animate);
42778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        }
42878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette    };
42978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette
430e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette    public interface OnDaySelectedListener {
43178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette        void onDaySelected(DayPickerView view, Calendar day);
432e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette    }
433bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio}
434