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 android.annotation.Nullable;
20bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.Context;
21bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.res.ColorStateList;
22bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.res.Configuration;
23bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.res.Resources;
24bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.res.TypedArray;
25ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viveretteimport android.icu.text.DateFormat;
26c3e5a82691ac9094189a000430eab939e9020b2bAlan Viveretteimport android.icu.text.DisplayContext;
2768763be41cffbcb4883a0a6293fc1aa9e17a3957Alan Viveretteimport android.icu.util.Calendar;
28bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.os.Parcelable;
29bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.util.AttributeSet;
300ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport android.util.StateSet;
31bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.HapticFeedbackConstants;
32bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.LayoutInflater;
33bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.View;
340ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport android.view.View.OnClickListener;
350ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport android.view.ViewGroup;
36bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityEvent;
370ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport android.widget.DayPickerView.OnDaySelectedListener;
380ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport android.widget.YearPickerView.OnYearSelectedListener;
39bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
4099441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikasimport com.android.internal.R;
4199441c5d7da45c10b729185852be97cbb0bdc8d5Aurimas Liutikas
42bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.Locale;
43bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
44bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio/**
45bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * A delegate for picking up a date (day / month / year).
46bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */
470ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteclass DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate {
480a04bb0d4bf18318fe5473bf5615c2016bc26373Alan Viverette    private static final int USE_LOCALE = 0;
49bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
50bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    private static final int UNINITIALIZED = -1;
510ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private static final int VIEW_MONTH_DAY = 0;
520ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private static final int VIEW_YEAR = 1;
53bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
54bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    private static final int DEFAULT_START_YEAR = 1900;
55bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    private static final int DEFAULT_END_YEAR = 2100;
56bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
57bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    private static final int ANIMATION_DURATION = 300;
58bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
5960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette    private static final int[] ATTRS_TEXT_COLOR = new int[] {
6060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette            com.android.internal.R.attr.textColor};
6160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette    private static final int[] ATTRS_DISABLED_ALPHA = new int[] {
620ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            com.android.internal.R.attr.disabledAlpha};
63bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
64ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette    private DateFormat mYearFormat;
65ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette    private DateFormat mMonthDayFormat;
667119d0d66bd8649508c5bbb973a34b3b858bf8cfAlan Viverette
670ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    // Top-level container.
680ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private ViewGroup mContainer;
697119d0d66bd8649508c5bbb973a34b3b858bf8cfAlan Viverette
700ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    // Header views.
710ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private TextView mHeaderYear;
720ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private TextView mHeaderMonthDay;
737119d0d66bd8649508c5bbb973a34b3b858bf8cfAlan Viverette
740ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    // Picker views.
750ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private ViewAnimator mAnimator;
76bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    private DayPickerView mDayPickerView;
77bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    private YearPickerView mYearPickerView;
78bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
79bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    // Accessibility strings.
80bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    private String mSelectDay;
81bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    private String mSelectYear;
82bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
83bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    private int mCurrentView = UNINITIALIZED;
84bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
85452fe349841476e4c7d17ab0652bdd4d45ce4595Alan Viverette    private final Calendar mTempDate;
86452fe349841476e4c7d17ab0652bdd4d45ce4595Alan Viverette    private final Calendar mMinDate;
87452fe349841476e4c7d17ab0652bdd4d45ce4595Alan Viverette    private final Calendar mMaxDate;
88bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
890a04bb0d4bf18318fe5473bf5615c2016bc26373Alan Viverette    private int mFirstDayOfWeek = USE_LOCALE;
900a04bb0d4bf18318fe5473bf5615c2016bc26373Alan Viverette
913053b2fdcf7486f2e2f572f9b05ce65dacdd2b4cChet Haase    public DatePickerCalendarDelegate(DatePicker delegator, Context context, AttributeSet attrs,
92bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            int defStyleAttr, int defStyleRes) {
93bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        super(delegator, context);
94bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
950ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final Locale locale = mCurrentLocale;
96452fe349841476e4c7d17ab0652bdd4d45ce4595Alan Viverette        mCurrentDate = Calendar.getInstance(locale);
97452fe349841476e4c7d17ab0652bdd4d45ce4595Alan Viverette        mTempDate = Calendar.getInstance(locale);
98452fe349841476e4c7d17ab0652bdd4d45ce4595Alan Viverette        mMinDate = Calendar.getInstance(locale);
99452fe349841476e4c7d17ab0652bdd4d45ce4595Alan Viverette        mMaxDate = Calendar.getInstance(locale);
100bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
10149e6c4adbfad8cac28a0c7c68918b443a64a07d8You Kim        mMinDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1);
10249e6c4adbfad8cac28a0c7c68918b443a64a07d8You Kim        mMaxDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31);
103bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
10460727e07c6ef72e2f494266939c02494a3df28f8Alan Viverette        final Resources res = mDelegator.getResources();
105bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        final TypedArray a = mContext.obtainStyledAttributes(attrs,
106bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                R.styleable.DatePicker, defStyleAttr, defStyleRes);
107bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
108bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                Context.LAYOUT_INFLATER_SERVICE);
109bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        final int layoutResourceId = a.getResourceId(
1100ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                R.styleable.DatePicker_internalLayout, R.layout.date_picker_material);
1110ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1120ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Set up and attach container.
113f7aa9251d091d0e52e879a8a92bd38228e58efd9Alan Viverette        mContainer = (ViewGroup) inflater.inflate(layoutResourceId, mDelegator, false);
11443da25c6707b7ddd118bf507865d21cebc4ae70bAdam Powell        mContainer.setSaveFromParentEnabled(false);
115f7aa9251d091d0e52e879a8a92bd38228e58efd9Alan Viverette        mDelegator.addView(mContainer);
116bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
1170ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Set up header views.
1188e1a72964517bfd01d8e650453ef41e22f770f21Alan Viverette        final ViewGroup header = mContainer.findViewById(R.id.date_picker_header);
1198e1a72964517bfd01d8e650453ef41e22f770f21Alan Viverette        mHeaderYear = header.findViewById(R.id.date_picker_header_year);
1200ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mHeaderYear.setOnClickListener(mOnHeaderClickListener);
1218e1a72964517bfd01d8e650453ef41e22f770f21Alan Viverette        mHeaderMonthDay = header.findViewById(R.id.date_picker_header_date);
1220ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mHeaderMonthDay.setOnClickListener(mOnHeaderClickListener);
123ba9bf41a77261471a4dc9d7964aec41726b4e4e6Alan Viverette
1240ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // For the sake of backwards compatibility, attempt to extract the text
1250ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // color from the header month text appearance. If it's set, we'll let
1260ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // that override the "real" header text color.
1270ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        ColorStateList headerTextColor = null;
128bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
1290ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        @SuppressWarnings("deprecation")
1300ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int monthHeaderTextAppearance = a.getResourceId(
1314e5168fae43e783a35c5bc731e500196005268fbAlan Viverette                R.styleable.DatePicker_headerMonthTextAppearance, 0);
1320ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (monthHeaderTextAppearance != 0) {
1330ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            final TypedArray textAppearance = mContext.obtainStyledAttributes(null,
1340ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                    ATTRS_TEXT_COLOR, 0, monthHeaderTextAppearance);
1350ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            final ColorStateList legacyHeaderTextColor = textAppearance.getColorStateList(0);
1360ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            headerTextColor = applyLegacyColorFixes(legacyHeaderTextColor);
1370ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            textAppearance.recycle();
138bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        }
13960727e07c6ef72e2f494266939c02494a3df28f8Alan Viverette
1400ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (headerTextColor == null) {
1410ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            headerTextColor = a.getColorStateList(R.styleable.DatePicker_headerTextColor);
14260727e07c6ef72e2f494266939c02494a3df28f8Alan Viverette        }
14360727e07c6ef72e2f494266939c02494a3df28f8Alan Viverette
1440ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (headerTextColor != null) {
1450ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            mHeaderYear.setTextColor(headerTextColor);
1460ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            mHeaderMonthDay.setTextColor(headerTextColor);
14760727e07c6ef72e2f494266939c02494a3df28f8Alan Viverette        }
148bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
1490ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Set up header background, if available.
1500ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (a.hasValueOrEmpty(R.styleable.DatePicker_headerBackground)) {
1510ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            header.setBackground(a.getDrawable(R.styleable.DatePicker_headerBackground));
1520ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
1530ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
15460b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette        a.recycle();
15560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette
1560ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Set up picker container.
1578e1a72964517bfd01d8e650453ef41e22f770f21Alan Viverette        mAnimator = mContainer.findViewById(R.id.animator);
1580ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1590ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Set up day picker view.
1608e1a72964517bfd01d8e650453ef41e22f770f21Alan Viverette        mDayPickerView = mAnimator.findViewById(R.id.date_picker_day_picker);
161e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette        mDayPickerView.setFirstDayOfWeek(mFirstDayOfWeek);
1624612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        mDayPickerView.setMinDate(mMinDate.getTimeInMillis());
1634612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        mDayPickerView.setMaxDate(mMaxDate.getTimeInMillis());
1644612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        mDayPickerView.setDate(mCurrentDate.getTimeInMillis());
165e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette        mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener);
16650eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette
1670ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Set up year picker view.
1688e1a72964517bfd01d8e650453ef41e22f770f21Alan Viverette        mYearPickerView = mAnimator.findViewById(R.id.date_picker_year_picker);
1692a90fa6d94b7d31e997493d2d0601e5129ec7c3eAlan Viverette        mYearPickerView.setRange(mMinDate, mMaxDate);
170e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount        mYearPickerView.setYear(mCurrentDate.get(Calendar.YEAR));
1710ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mYearPickerView.setOnYearSelectedListener(mOnYearSelectedListener);
1724e5168fae43e783a35c5bc731e500196005268fbAlan Viverette
1730ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Set up content descriptions.
174bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        mSelectDay = res.getString(R.string.select_day);
175bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        mSelectYear = res.getString(R.string.select_year);
176bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
1770ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Initialize for current locale. This also initializes the date, so no
1780ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // need to call onDateChanged.
1790ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        onLocaleChanged(mCurrentLocale);
1800ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1810ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setCurrentView(VIEW_MONTH_DAY);
1820ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
1830ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1840ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    /**
1850ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * The legacy text color might have been poorly defined. Ensures that it
1860ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * has an appropriate activated state, using the selected state if one
1870ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * exists or modifying the default text color otherwise.
1880ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     *
1890ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * @param color a legacy text color, or {@code null}
1900ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * @return a color state list with an appropriate activated state, or
1910ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     *         {@code null} if a valid activated state could not be generated
1920ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     */
1930ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    @Nullable
1940ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private ColorStateList applyLegacyColorFixes(@Nullable ColorStateList color) {
1950ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (color == null || color.hasState(R.attr.state_activated)) {
1960ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            return color;
1970ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
1980ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
1990ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int activatedColor;
2000ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int defaultColor;
2010ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (color.hasState(R.attr.state_selected)) {
2020ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            activatedColor = color.getColorForState(StateSet.get(
2030ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                    StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_SELECTED), 0);
2040ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            defaultColor = color.getColorForState(StateSet.get(
2050ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                    StateSet.VIEW_STATE_ENABLED), 0);
2060ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        } else {
2070ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            activatedColor = color.getDefaultColor();
2080ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2090ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            // Generate a non-activated color using the disabled alpha.
2100ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            final TypedArray ta = mContext.obtainStyledAttributes(ATTRS_DISABLED_ALPHA);
2110ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            final float disabledAlpha = ta.getFloat(0, 0.30f);
2120ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            defaultColor = multiplyAlphaComponent(activatedColor, disabledAlpha);
2130ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
2147119d0d66bd8649508c5bbb973a34b3b858bf8cfAlan Viverette
2150ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (activatedColor == 0 || defaultColor == 0) {
2160ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            // We somehow failed to obtain the colors.
2170ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            return null;
2180ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
2197119d0d66bd8649508c5bbb973a34b3b858bf8cfAlan Viverette
2200ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int[][] stateSet = new int[][] {{ R.attr.state_activated }, {}};
2210ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int[] colors = new int[] { activatedColor, defaultColor };
2220ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        return new ColorStateList(stateSet, colors);
2230ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
224bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
2250ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private int multiplyAlphaComponent(int color, float alphaMod) {
2260ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int srcRgb = color & 0xFFFFFF;
2270ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int srcAlpha = (color >> 24) & 0xFF;
2280ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int dstAlpha = (int) (srcAlpha * alphaMod + 0.5f);
2290ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        return srcRgb | (dstAlpha << 24);
230bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
231bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
232bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    /**
2330ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * Listener called when the user selects a day in the day picker view.
2340ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     */
2350ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private final OnDaySelectedListener mOnDaySelectedListener = new OnDaySelectedListener() {
2360ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        @Override
2370ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        public void onDaySelected(DayPickerView view, Calendar day) {
2380ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            mCurrentDate.setTimeInMillis(day.getTimeInMillis());
2390ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            onDateChanged(true, true);
2400ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
2410ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    };
2420ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2430ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    /**
2440ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * Listener called when the user selects a year in the year picker view.
2450ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     */
2460ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private final OnYearSelectedListener mOnYearSelectedListener = new OnYearSelectedListener() {
2470ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        @Override
2480ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        public void onYearChanged(YearPickerView view, int year) {
2490ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            // If the newly selected month / year does not contain the
2500ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            // currently selected day number, change the selected day number
2510ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            // to the last day of the selected month or year.
2520ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            // e.g. Switching from Mar to Apr when Mar 31 is selected -> Apr 30
2530ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            // e.g. Switching from 2012 to 2013 when Feb 29, 2012 is selected -> Feb 28, 2013
2540ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            final int day = mCurrentDate.get(Calendar.DAY_OF_MONTH);
2550ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            final int month = mCurrentDate.get(Calendar.MONTH);
2560ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            final int daysInMonth = getDaysInMonth(month, year);
2570ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            if (day > daysInMonth) {
2580ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                mCurrentDate.set(Calendar.DAY_OF_MONTH, daysInMonth);
2590ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            }
2600ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2610ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            mCurrentDate.set(Calendar.YEAR, year);
2620ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            onDateChanged(true, true);
2630ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2640ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            // Automatically switch to day picker.
2650ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            setCurrentView(VIEW_MONTH_DAY);
266e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount
267e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount            // Switch focus back to the year text.
268e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount            mHeaderYear.requestFocus();
2690ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
2700ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    };
2710ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2720ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    /**
2730ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     * Listener called when the user clicks on a header item.
2740ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette     */
275ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette    private final OnClickListener mOnHeaderClickListener = v -> {
276ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette        tryVibrate();
277ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette
278ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette        switch (v.getId()) {
279ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette            case R.id.date_picker_header_year:
280ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette                setCurrentView(VIEW_YEAR);
281ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette                break;
282ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette            case R.id.date_picker_header_date:
283ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette                setCurrentView(VIEW_MONTH_DAY);
284ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette                break;
2850ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        }
2860ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    };
2870ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
2880ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    @Override
2890ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    protected void onLocaleChanged(Locale locale) {
2900ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final TextView headerYear = mHeaderYear;
2910ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (headerYear == null) {
2920ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            // Abort, we haven't initialized yet. This method will get called
2930ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            // again later after everything has been set up.
2940ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            return;
295bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        }
296bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
2970ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Update the date formatter.
298ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette        mMonthDayFormat = DateFormat.getInstanceForSkeleton("EMMMd", locale);
299c3e5a82691ac9094189a000430eab939e9020b2bAlan Viverette        mMonthDayFormat.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE);
300ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette        mYearFormat = DateFormat.getInstanceForSkeleton("y", locale);
301bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
3020ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // Update the header text.
3030ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        onCurrentDateChanged(false);
3040ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    }
305bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
3060ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private void onCurrentDateChanged(boolean announce) {
3070ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (mHeaderYear == null) {
3080ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            // Abort, we haven't initialized yet. This method will get called
3090ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            // again later after everything has been set up.
3100ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            return;
311bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        }
312bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
3130ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final String year = mYearFormat.format(mCurrentDate.getTime());
3140ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mHeaderYear.setText(year);
315bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
3160ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final String monthDay = mMonthDayFormat.format(mCurrentDate.getTime());
3170ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mHeaderMonthDay.setText(monthDay);
318bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
3190ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        // TODO: This should use live regions.
320bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        if (announce) {
321dd80f0065c0088bff30f9ce5e166df47ddf10690Andrei Stingaceanu            mAnimator.announceForAccessibility(getFormattedCurrentDate());
322bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        }
323bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
324bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
325bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    private void setCurrentView(final int viewIndex) {
326bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        switch (viewIndex) {
3270ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            case VIEW_MONTH_DAY:
3280ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                mDayPickerView.setDate(mCurrentDate.getTimeInMillis());
3290ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
330bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                if (mCurrentView != viewIndex) {
3310ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                    mHeaderMonthDay.setActivated(true);
3320ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                    mHeaderYear.setActivated(false);
3330ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                    mAnimator.setDisplayedChild(VIEW_MONTH_DAY);
334bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                    mCurrentView = viewIndex;
335bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                }
336bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
337bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                mAnimator.announceForAccessibility(mSelectDay);
338bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                break;
3390ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette            case VIEW_YEAR:
340e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount                final int year = mCurrentDate.get(Calendar.YEAR);
341e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount                mYearPickerView.setYear(year);
342ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette                mYearPickerView.post(() -> {
343ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette                    mYearPickerView.requestFocus();
344ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette                    final View selected = mYearPickerView.getSelectedView();
345ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette                    if (selected != null) {
346ca38c43604162e0dd532bec675e67f18fd400ae8Alan Viverette                        selected.requestFocus();
347e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount                    }
348e998c3f5f6e7ac21b18cd449088ac2b76b65671fGeorge Mount                });
3490ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
350bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                if (mCurrentView != viewIndex) {
3510ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                    mHeaderMonthDay.setActivated(false);
3520ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                    mHeaderYear.setActivated(true);
3530ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette                    mAnimator.setDisplayedChild(VIEW_YEAR);
354bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                    mCurrentView = viewIndex;
355bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                }
356bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
357bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                mAnimator.announceForAccessibility(mSelectYear);
358bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                break;
359bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        }
360bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
361bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
362bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
363f480e8cad5e6cf4fed85a944adc01d96f51e966bFelipe Leme    public void init(int year, int month, int dayOfMonth,
364bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            DatePicker.OnDateChangedListener callBack) {
365f480e8cad5e6cf4fed85a944adc01d96f51e966bFelipe Leme        setDate(year, month, dayOfMonth);
3660cecbc9c7208f918ddf9d117057649f6e132069fAlan Viverette        onDateChanged(false, false);
367a9a75f506efe7e63078bed661f49992e501846f0Alan Viverette
36868640b68099765461d5427fddbb925beaa9d2a6aClara Bayarri        mOnDateChangedListener = callBack;
369bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
370bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
371bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
372bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public void updateDate(int year, int month, int dayOfMonth) {
373f480e8cad5e6cf4fed85a944adc01d96f51e966bFelipe Leme        setDate(year, month, dayOfMonth);
374f480e8cad5e6cf4fed85a944adc01d96f51e966bFelipe Leme        onDateChanged(false, true);
375f480e8cad5e6cf4fed85a944adc01d96f51e966bFelipe Leme    }
376f480e8cad5e6cf4fed85a944adc01d96f51e966bFelipe Leme
377f480e8cad5e6cf4fed85a944adc01d96f51e966bFelipe Leme    private void setDate(int year, int month, int dayOfMonth) {
378bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        mCurrentDate.set(Calendar.YEAR, year);
379bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        mCurrentDate.set(Calendar.MONTH, month);
380bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
381f480e8cad5e6cf4fed85a944adc01d96f51e966bFelipe Leme        resetAutofilledValue();
382e6ec07fc5d7ce7732f63b6da73d3cc9e207df69fAlan Viverette    }
383e6ec07fc5d7ce7732f63b6da73d3cc9e207df69fAlan Viverette
3840cecbc9c7208f918ddf9d117057649f6e132069fAlan Viverette    private void onDateChanged(boolean fromUser, boolean callbackToClient) {
3850ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        final int year = mCurrentDate.get(Calendar.YEAR);
3860ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette
387305b72c92568a2dd2ece08caebd610ec8bd473f4Felipe Leme        if (callbackToClient
388305b72c92568a2dd2ece08caebd610ec8bd473f4Felipe Leme                && (mOnDateChangedListener != null || mAutoFillChangeListener != null)) {
389e6ec07fc5d7ce7732f63b6da73d3cc9e207df69fAlan Viverette            final int monthOfYear = mCurrentDate.get(Calendar.MONTH);
390e6ec07fc5d7ce7732f63b6da73d3cc9e207df69fAlan Viverette            final int dayOfMonth = mCurrentDate.get(Calendar.DAY_OF_MONTH);
391305b72c92568a2dd2ece08caebd610ec8bd473f4Felipe Leme            if (mOnDateChangedListener != null) {
392305b72c92568a2dd2ece08caebd610ec8bd473f4Felipe Leme                mOnDateChangedListener.onDateChanged(mDelegator, year, monthOfYear, dayOfMonth);
393305b72c92568a2dd2ece08caebd610ec8bd473f4Felipe Leme            }
394305b72c92568a2dd2ece08caebd610ec8bd473f4Felipe Leme            if (mAutoFillChangeListener != null) {
395305b72c92568a2dd2ece08caebd610ec8bd473f4Felipe Leme                mAutoFillChangeListener.onDateChanged(mDelegator, year, monthOfYear, dayOfMonth);
396305b72c92568a2dd2ece08caebd610ec8bd473f4Felipe Leme            }
397e6ec07fc5d7ce7732f63b6da73d3cc9e207df69fAlan Viverette        }
398e6ec07fc5d7ce7732f63b6da73d3cc9e207df69fAlan Viverette
3990ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mDayPickerView.setDate(mCurrentDate.getTimeInMillis());
4000ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        mYearPickerView.setYear(year);
401e6ec07fc5d7ce7732f63b6da73d3cc9e207df69fAlan Viverette
4020ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        onCurrentDateChanged(fromUser);
403e6ec07fc5d7ce7732f63b6da73d3cc9e207df69fAlan Viverette
404e6ec07fc5d7ce7732f63b6da73d3cc9e207df69fAlan Viverette        if (fromUser) {
405e6ec07fc5d7ce7732f63b6da73d3cc9e207df69fAlan Viverette            tryVibrate();
4069468c6a28e696f4ddca2c5b9ba312ffb590c3161Alan Viverette        }
407bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
408bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
409bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
410bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public int getYear() {
411bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        return mCurrentDate.get(Calendar.YEAR);
412bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
413bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
414bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
415bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public int getMonth() {
416bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        return mCurrentDate.get(Calendar.MONTH);
417bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
418bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
419bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
420bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public int getDayOfMonth() {
421bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        return mCurrentDate.get(Calendar.DAY_OF_MONTH);
422bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
423bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
424bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
425bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public void setMinDate(long minDate) {
426bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        mTempDate.setTimeInMillis(minDate);
427bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR)
4283fb5c7b8fac6fd5583da10793d0bfa40bc851ed5Alan Viverette                && mTempDate.get(Calendar.DAY_OF_YEAR) == mMinDate.get(Calendar.DAY_OF_YEAR)) {
4293fb5c7b8fac6fd5583da10793d0bfa40bc851ed5Alan Viverette            // Same day, no-op.
430bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            return;
431bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        }
432bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        if (mCurrentDate.before(mTempDate)) {
433bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            mCurrentDate.setTimeInMillis(minDate);
4340cecbc9c7208f918ddf9d117057649f6e132069fAlan Viverette            onDateChanged(false, true);
435bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        }
436bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        mMinDate.setTimeInMillis(minDate);
4374612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        mDayPickerView.setMinDate(minDate);
43850eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette        mYearPickerView.setRange(mMinDate, mMaxDate);
439bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
440bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
441bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
442bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public Calendar getMinDate() {
443bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        return mMinDate;
444bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
445bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
446bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
447bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public void setMaxDate(long maxDate) {
448bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        mTempDate.setTimeInMillis(maxDate);
449bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)
4503fb5c7b8fac6fd5583da10793d0bfa40bc851ed5Alan Viverette                && mTempDate.get(Calendar.DAY_OF_YEAR) == mMaxDate.get(Calendar.DAY_OF_YEAR)) {
4513fb5c7b8fac6fd5583da10793d0bfa40bc851ed5Alan Viverette            // Same day, no-op.
452bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            return;
453bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        }
454bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        if (mCurrentDate.after(mTempDate)) {
455bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            mCurrentDate.setTimeInMillis(maxDate);
4560cecbc9c7208f918ddf9d117057649f6e132069fAlan Viverette            onDateChanged(false, true);
457bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        }
458bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        mMaxDate.setTimeInMillis(maxDate);
4594612740ddc76b3518dc6d189d5f8b5b7f60e9d64Alan Viverette        mDayPickerView.setMaxDate(maxDate);
46050eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette        mYearPickerView.setRange(mMinDate, mMaxDate);
461bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
462bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
463bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
464bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public Calendar getMaxDate() {
465bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        return mMaxDate;
466bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
467bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
468bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
4690a04bb0d4bf18318fe5473bf5615c2016bc26373Alan Viverette    public void setFirstDayOfWeek(int firstDayOfWeek) {
4700a04bb0d4bf18318fe5473bf5615c2016bc26373Alan Viverette        mFirstDayOfWeek = firstDayOfWeek;
471e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette
472e763c9bd6ed0ca46daafc21fc4313ebcad4bcafaAlan Viverette        mDayPickerView.setFirstDayOfWeek(firstDayOfWeek);
4730a04bb0d4bf18318fe5473bf5615c2016bc26373Alan Viverette    }
4740a04bb0d4bf18318fe5473bf5615c2016bc26373Alan Viverette
4750a04bb0d4bf18318fe5473bf5615c2016bc26373Alan Viverette    @Override
476bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public int getFirstDayOfWeek() {
4770a04bb0d4bf18318fe5473bf5615c2016bc26373Alan Viverette        if (mFirstDayOfWeek != USE_LOCALE) {
4780a04bb0d4bf18318fe5473bf5615c2016bc26373Alan Viverette            return mFirstDayOfWeek;
4790a04bb0d4bf18318fe5473bf5615c2016bc26373Alan Viverette        }
480bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        return mCurrentDate.getFirstDayOfWeek();
481bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
482bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
483bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
484bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public void setEnabled(boolean enabled) {
485f7aa9251d091d0e52e879a8a92bd38228e58efd9Alan Viverette        mContainer.setEnabled(enabled);
486f7aa9251d091d0e52e879a8a92bd38228e58efd9Alan Viverette        mDayPickerView.setEnabled(enabled);
487f7aa9251d091d0e52e879a8a92bd38228e58efd9Alan Viverette        mYearPickerView.setEnabled(enabled);
488f7aa9251d091d0e52e879a8a92bd38228e58efd9Alan Viverette        mHeaderYear.setEnabled(enabled);
489f7aa9251d091d0e52e879a8a92bd38228e58efd9Alan Viverette        mHeaderMonthDay.setEnabled(enabled);
490bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
491bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
492bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
493bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public boolean isEnabled() {
4940ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        return mContainer.isEnabled();
495bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
496bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
497bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
498bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public CalendarView getCalendarView() {
499f7aa9251d091d0e52e879a8a92bd38228e58efd9Alan Viverette        throw new UnsupportedOperationException("Not supported by calendar-mode DatePicker");
500bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
501bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
502bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
503bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public void setCalendarViewShown(boolean shown) {
504bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        // No-op for compatibility with the old DatePicker.
505bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
506bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
507bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
508bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public boolean getCalendarViewShown() {
509bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        return false;
510bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
511bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
512bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
513bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public void setSpinnersShown(boolean shown) {
514bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        // No-op for compatibility with the old DatePicker.
515bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
516bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
517bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
518bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public boolean getSpinnersShown() {
519bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        return false;
520bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
521bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
522bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
523bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public void onConfigurationChanged(Configuration newConfig) {
5240ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        setCurrentLocale(newConfig.locale);
525bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
526bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
527bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
528bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public Parcelable onSaveInstanceState(Parcelable superState) {
529bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        final int year = mCurrentDate.get(Calendar.YEAR);
530bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        final int month = mCurrentDate.get(Calendar.MONTH);
531bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        final int day = mCurrentDate.get(Calendar.DAY_OF_MONTH);
532bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
533bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        int listPosition = -1;
534bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        int listPositionOffset = -1;
535bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
5360ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        if (mCurrentView == VIEW_MONTH_DAY) {
537bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            listPosition = mDayPickerView.getMostVisiblePosition();
5380ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette        } else if (mCurrentView == VIEW_YEAR) {
539bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            listPosition = mYearPickerView.getFirstVisiblePosition();
540bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            listPositionOffset = mYearPickerView.getFirstPositionOffset();
541bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        }
542bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
543bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        return new SavedState(superState, year, month, day, mMinDate.getTimeInMillis(),
544bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                mMaxDate.getTimeInMillis(), mCurrentView, listPosition, listPositionOffset);
545bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
546bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
547bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
548bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public void onRestoreInstanceState(Parcelable state) {
5496b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette        if (state instanceof SavedState) {
5506b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette            final SavedState ss = (SavedState) state;
5516b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette
5526b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette            // TODO: Move instance state into DayPickerView, YearPickerView.
5536b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette            mCurrentDate.set(ss.getSelectedYear(), ss.getSelectedMonth(), ss.getSelectedDay());
5546b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette            mMinDate.setTimeInMillis(ss.getMinDate());
5556b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette            mMaxDate.setTimeInMillis(ss.getMaxDate());
5566b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette
5576b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette            onCurrentDateChanged(false);
5586b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette
5596b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette            final int currentView = ss.getCurrentView();
5606b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette            setCurrentView(currentView);
5616b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette
5626b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette            final int listPosition = ss.getListPosition();
5636b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette            if (listPosition != -1) {
5646b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette                if (currentView == VIEW_MONTH_DAY) {
5656b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette                    mDayPickerView.setPosition(listPosition);
5666b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette                } else if (currentView == VIEW_YEAR) {
5676b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette                    final int listPositionOffset = ss.getListPositionOffset();
5686b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette                    mYearPickerView.setSelectionFromTop(listPosition, listPositionOffset);
5696b3f85f87ed95cce748aeb57c70df0d2ed72707fAlan Viverette                }
570bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            }
571bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        }
572bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
573bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
574bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    @Override
575bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
576bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        onPopulateAccessibilityEvent(event);
577bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        return true;
578bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
579bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
580a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn    public CharSequence getAccessibilityClassName() {
581a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn        return DatePicker.class.getName();
582bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
583bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
584bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    public static int getDaysInMonth(int month, int year) {
585bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        switch (month) {
586bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            case Calendar.JANUARY:
587bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            case Calendar.MARCH:
588bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            case Calendar.MAY:
589bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            case Calendar.JULY:
590bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            case Calendar.AUGUST:
591bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            case Calendar.OCTOBER:
592bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            case Calendar.DECEMBER:
593bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                return 31;
594bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            case Calendar.APRIL:
595bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            case Calendar.JUNE:
596bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            case Calendar.SEPTEMBER:
597bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            case Calendar.NOVEMBER:
598bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                return 30;
599bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            case Calendar.FEBRUARY:
600bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                return (year % 4 == 0) ? 29 : 28;
601bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio            default:
602bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio                throw new IllegalArgumentException("Invalid Month");
603bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        }
604bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
605bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio
6060ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette    private void tryVibrate() {
607bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio        mDelegator.performHapticFeedback(HapticFeedbackConstants.CALENDAR_DATE);
608bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio    }
609bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio}
610