12946445b560fde5e63df17f5a2db60c8349fe532Romain Guy/*
22946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * Copyright (C) 2012 The Android Open Source Project
32946445b560fde5e63df17f5a2db60c8349fe532Romain Guy *
42946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * Licensed under the Apache License, Version 2.0 (the "License");
52946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * you may not use this file except in compliance with the License.
62946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * You may obtain a copy of the License at
72946445b560fde5e63df17f5a2db60c8349fe532Romain Guy *
82946445b560fde5e63df17f5a2db60c8349fe532Romain Guy *      http://www.apache.org/licenses/LICENSE-2.0
92946445b560fde5e63df17f5a2db60c8349fe532Romain Guy *
102946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * Unless required by applicable law or agreed to in writing, software
112946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * distributed under the License is distributed on an "AS IS" BASIS,
122946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * See the License for the specific language governing permissions and
142946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * limitations under the License.
152946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */
162946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
172946445b560fde5e63df17f5a2db60c8349fe532Romain Guypackage com.android.test.hwui;
182946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
192946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.annotation.Widget;
202946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.content.Context;
212946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.content.res.TypedArray;
222946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.os.Parcel;
232946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.os.Parcelable;
242946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.text.format.DateFormat;
252946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.util.AttributeSet;
262946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.util.SparseArray;
272946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.view.ContextThemeWrapper;
282946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.view.LayoutInflater;
292946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.view.View;
302946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.widget.CheckBox;
312946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.widget.CompoundButton;
322946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.widget.FrameLayout;
332946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.widget.LinearLayout;
342946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.widget.NumberPicker;
352946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
362946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport java.text.DateFormatSymbols;
372946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport java.text.SimpleDateFormat;
382946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport java.util.Calendar;
392946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
402946445b560fde5e63df17f5a2db60c8349fe532Romain Guy/**
412946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * A view for selecting a month / year / day based on a calendar like layout.
422946445b560fde5e63df17f5a2db60c8349fe532Romain Guy *
432946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Date Picker
442946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * tutorial</a>.</p>
452946445b560fde5e63df17f5a2db60c8349fe532Romain Guy *
462946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * For a dialog using this view, see {@link android.app.DatePickerDialog}.
472946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */
482946445b560fde5e63df17f5a2db60c8349fe532Romain Guy@Widget
492946445b560fde5e63df17f5a2db60c8349fe532Romain Guypublic class DatePicker extends FrameLayout {
502946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
512946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private static final int DEFAULT_START_YEAR = 1900;
522946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private static final int DEFAULT_END_YEAR = 2100;
532946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
542946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    /* UI Components */
552946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private final CheckBox mYearToggle;
562946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private final NumberPicker mDayPicker;
572946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private final NumberPicker mMonthPicker;
582946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private final NumberPicker mYearPicker;
592946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
602946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    /**
612946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     * How we notify users the date has changed.
622946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     */
632946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private OnDateChangedListener mOnDateChangedListener;
642946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
652946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private int mDay;
662946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private int mMonth;
672946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private int mYear;
682946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private boolean mYearOptional = true;
692946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private boolean mHasYear;
702946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
712946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    /**
722946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     * The callback used to indicate the user changes the date.
732946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     */
742946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    public interface OnDateChangedListener {
752946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
762946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        /**
772946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         * @param view The view associated with this listener.
782946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         * @param year The year that was set.
792946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         * @param monthOfYear The month that was set (0-11) for compatibility
802946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         *  with {@link java.util.Calendar}.
812946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         * @param dayOfMonth The day of the month that was set.
822946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         */
832946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth);
842946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
852946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
862946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    public DatePicker(Context context) {
872946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        this(context, null);
882946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
892946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
902946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    public DatePicker(Context context, AttributeSet attrs) {
912946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        this(context, attrs, 0);
922946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
932946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
942946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    @SuppressWarnings("deprecation")
952946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    public DatePicker(Context context, AttributeSet attrs, int defStyle) {
962946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        super(context, attrs, defStyle);
972946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
982946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        ContextThemeWrapper themed = new ContextThemeWrapper(context,
992946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                com.android.internal.R.style.Theme_Holo_Light_Dialog_Alert);
1002946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        LayoutInflater inflater = (LayoutInflater) themed.getSystemService(
1012946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                        Context.LAYOUT_INFLATER_SERVICE);
1022946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        inflater.inflate(R.layout.date_picker, this, true);
1032946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
1042946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mDayPicker = (NumberPicker) findViewById(R.id.day);
105d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio        mDayPicker.setFormatter(NumberPicker.getTwoDigitFormatter());
1062946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mDayPicker.setOnLongPressUpdateInterval(100);
1072946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mDayPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
1082946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
1092946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                mDay = newVal;
1102946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                notifyDateChanged();
1112946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            }
1122946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        });
1132946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mMonthPicker = (NumberPicker) findViewById(R.id.month);
114d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio        mMonthPicker.setFormatter(NumberPicker.getTwoDigitFormatter());
1152946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        DateFormatSymbols dfs = new DateFormatSymbols();
1162946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        String[] months = dfs.getShortMonths();
1172946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
1182946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        /*
1192946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         * If the user is in a locale where the month names are numeric,
1202946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         * use just the number instead of the "month" character for
1212946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         * consistency with the other fields.
1222946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         */
1232946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        if (months[0].startsWith("1")) {
1242946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            for (int i = 0; i < months.length; i++) {
1252946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                months[i] = String.valueOf(i + 1);
1262946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            }
1272946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mMonthPicker.setMinValue(1);
1282946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mMonthPicker.setMaxValue(12);
1292946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        } else {
1302946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mMonthPicker.setMinValue(1);
1312946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mMonthPicker.setMaxValue(12);
1322946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mMonthPicker.setDisplayedValues(months);
1332946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
1342946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
1352946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mMonthPicker.setOnLongPressUpdateInterval(200);
1362946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mMonthPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
1372946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
1382946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
1392946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                /* We display the month 1-12 but store it 0-11 so always
1402946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                 * subtract by one to ensure our internal state is always 0-11
1412946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                 */
1422946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                mMonth = newVal - 1;
1432946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                // Adjust max day of the month
1442946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                adjustMaxDay();
1452946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                notifyDateChanged();
1462946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                updateDaySpinner();
1472946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            }
1482946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        });
1492946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYearPicker = (NumberPicker) findViewById(R.id.year);
1502946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYearPicker.setOnLongPressUpdateInterval(100);
1512946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYearPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
1522946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
1532946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                mYear = newVal;
1542946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                // Adjust max day for leap years if needed
1552946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                adjustMaxDay();
1562946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                notifyDateChanged();
1572946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                updateDaySpinner();
1582946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            }
1592946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        });
1602946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
1612946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYearToggle = (CheckBox) findViewById(R.id.yearToggle);
1622946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYearToggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
1632946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            @Override
1642946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1652946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                mHasYear = isChecked;
1662946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                adjustMaxDay();
1672946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                notifyDateChanged();
1682946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                updateSpinners();
1692946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            }
1702946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        });
1712946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
1722946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        // attributes
1732946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        TypedArray a = context.obtainStyledAttributes(attrs,
1742946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                com.android.internal.R.styleable.DatePicker);
1752946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
1762946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        int mStartYear =
1772946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                a.getInt(com.android.internal.R.styleable.DatePicker_startYear, DEFAULT_START_YEAR);
1782946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        int mEndYear =
1792946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                a.getInt(com.android.internal.R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
1802946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYearPicker.setMinValue(mStartYear);
1812946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYearPicker.setMaxValue(mEndYear);
1822946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
1832946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        a.recycle();
1842946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
1852946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        // initialize to current date
1862946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        Calendar cal = Calendar.getInstance();
1872946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        init(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), null);
1882946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
1892946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        // re-order the number pickers to match the current date format
1902946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        reorderPickers(months);
1912946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
1922946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        if (!isEnabled()) {
1932946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            setEnabled(false);
1942946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
1952946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
1962946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
1972946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    @Override
1982946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    public void setEnabled(boolean enabled) {
1992946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        super.setEnabled(enabled);
2002946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mDayPicker.setEnabled(enabled);
2012946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mMonthPicker.setEnabled(enabled);
2022946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYearPicker.setEnabled(enabled);
2032946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
2042946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
2052946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private void reorderPickers(String[] months) {
2062946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        java.text.DateFormat format;
2072946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        String order;
2082946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
2092946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        /*
2102946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         * If the user is in a locale where the medium date format is
2112946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         * still numeric (Japanese and Czech, for example), respect
2122946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         * the date format order setting.  Otherwise, use the order
2132946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         * that the locale says is appropriate for a spelled-out date.
2142946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         */
2152946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
2162946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        if (months[0].startsWith("1")) {
2172946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            format = DateFormat.getDateFormat(getContext());
2182946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        } else {
2192946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            format = DateFormat.getMediumDateFormat(getContext());
2202946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
2212946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
2222946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        if (format instanceof SimpleDateFormat) {
2232946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            order = ((SimpleDateFormat) format).toPattern();
2242946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        } else {
2252946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            // Shouldn't happen, but just in case.
2262946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            order = new String(DateFormat.getDateFormatOrder(getContext()));
2272946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
2282946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
2292946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        /* Remove the 3 pickers from their parent and then add them back in the
2302946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         * required order.
2312946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         */
2322946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        LinearLayout parent = (LinearLayout) findViewById(R.id.parent);
2332946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        parent.removeAllViews();
2342946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
2352946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        boolean quoted = false;
2362946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        boolean didDay = false, didMonth = false, didYear = false;
2372946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
2382946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        for (int i = 0; i < order.length(); i++) {
2392946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            char c = order.charAt(i);
2402946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
2412946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            if (c == '\'') {
2422946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                quoted = !quoted;
2432946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            }
2442946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
2452946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            if (!quoted) {
2462946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                if (c == DateFormat.DATE && !didDay) {
2472946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                    parent.addView(mDayPicker);
2482946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                    didDay = true;
2492946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                } else if ((c == DateFormat.MONTH || c == 'L') && !didMonth) {
2502946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                    parent.addView(mMonthPicker);
2512946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                    didMonth = true;
2522946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                } else if (c == DateFormat.YEAR && !didYear) {
2532946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                    parent.addView (mYearPicker);
2542946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                    didYear = true;
2552946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                }
2562946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            }
2572946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
2582946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
2592946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        // Shouldn't happen, but just in case.
2602946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        if (!didMonth) {
2612946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            parent.addView(mMonthPicker);
2622946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
2632946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        if (!didDay) {
2642946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            parent.addView(mDayPicker);
2652946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
2662946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        if (!didYear) {
2672946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            parent.addView(mYearPicker);
2682946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
2692946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
2702946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
2712946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    public void updateDate(int year, int monthOfYear, int dayOfMonth) {
2722946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        if (mYear != year || mMonth != monthOfYear || mDay != dayOfMonth) {
2732946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mYear = (mYearOptional && year == 0) ? getCurrentYear() : year;
2742946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mMonth = monthOfYear;
2752946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mDay = dayOfMonth;
2762946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            updateSpinners();
2772946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            reorderPickers(new DateFormatSymbols().getShortMonths());
2782946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            notifyDateChanged();
2792946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
2802946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
2812946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
2822946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private static int getCurrentYear() {
2832946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        return Calendar.getInstance().get(Calendar.YEAR);
2842946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
2852946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
2862946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private static class SavedState extends BaseSavedState {
2872946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
2882946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        private final int mYear;
2892946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        private final int mMonth;
2902946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        private final int mDay;
2912946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        private final boolean mHasYear;
2922946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        private final boolean mYearOptional;
2932946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
2942946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        /**
2952946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         * Constructor called from {@link DatePicker#onSaveInstanceState()}
2962946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         */
2972946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        private SavedState(Parcelable superState, int year, int month, int day, boolean hasYear,
2982946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                boolean yearOptional) {
2992946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            super(superState);
3002946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mYear = year;
3012946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mMonth = month;
3022946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mDay = day;
3032946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mHasYear = hasYear;
3042946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mYearOptional = yearOptional;
3052946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
3062946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3072946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        /**
3082946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         * Constructor called from {@link #CREATOR}
3092946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         */
3102946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        private SavedState(Parcel in) {
3112946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            super(in);
3122946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mYear = in.readInt();
3132946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mMonth = in.readInt();
3142946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mDay = in.readInt();
3152946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mHasYear = in.readInt() != 0;
3162946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mYearOptional = in.readInt() != 0;
3172946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
3182946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3192946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        public int getYear() {
3202946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            return mYear;
3212946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
3222946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3232946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        public int getMonth() {
3242946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            return mMonth;
3252946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
3262946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3272946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        public int getDay() {
3282946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            return mDay;
3292946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
3302946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3312946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        public boolean hasYear() {
3322946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            return mHasYear;
3332946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
3342946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3352946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        public boolean isYearOptional() {
3362946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            return mYearOptional;
3372946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
3382946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3392946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        @Override
3402946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        public void writeToParcel(Parcel dest, int flags) {
3412946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            super.writeToParcel(dest, flags);
3422946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            dest.writeInt(mYear);
3432946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            dest.writeInt(mMonth);
3442946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            dest.writeInt(mDay);
3452946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            dest.writeInt(mHasYear ? 1 : 0);
3462946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            dest.writeInt(mYearOptional ? 1 : 0);
3472946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
3482946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3492946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        @SuppressWarnings("unused")
3502946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        public static final Parcelable.Creator<SavedState> CREATOR =
3512946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                new Creator<SavedState>() {
3522946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3532946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                    public SavedState createFromParcel(Parcel in) {
3542946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                        return new SavedState(in);
3552946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                    }
3562946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3572946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                    public SavedState[] newArray(int size) {
3582946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                        return new SavedState[size];
3592946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                    }
3602946445b560fde5e63df17f5a2db60c8349fe532Romain Guy                };
3612946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
3622946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3632946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3642946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    /**
3652946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     * Override so we are in complete control of save / restore for this widget.
3662946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     */
3672946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    @Override
3682946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
3692946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        dispatchThawSelfOnly(container);
3702946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
3712946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3722946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    @Override
3732946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    protected Parcelable onSaveInstanceState() {
3742946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        Parcelable superState = super.onSaveInstanceState();
3752946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3762946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        return new SavedState(superState, mYear, mMonth, mDay, mHasYear, mYearOptional);
3772946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
3782946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3792946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    @Override
3802946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    protected void onRestoreInstanceState(Parcelable state) {
3812946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        SavedState ss = (SavedState) state;
3822946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        super.onRestoreInstanceState(ss.getSuperState());
3832946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYear = ss.getYear();
3842946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mMonth = ss.getMonth();
3852946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mDay = ss.getDay();
3862946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mHasYear = ss.hasYear();
3872946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYearOptional = ss.isYearOptional();
3882946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        updateSpinners();
3892946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
3902946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
3912946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    /**
3922946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     * Initialize the state.
3932946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     * @param year The initial year.
3942946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     * @param monthOfYear The initial month.
3952946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     * @param dayOfMonth The initial day of the month.
3962946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     * @param onDateChangedListener How user is notified date is changed by user, can be null.
3972946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     */
3982946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    public void init(int year, int monthOfYear, int dayOfMonth,
3992946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            OnDateChangedListener onDateChangedListener) {
4002946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        init(year, monthOfYear, dayOfMonth, false, onDateChangedListener);
4012946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
4022946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
4032946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    /**
4042946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     * Initialize the state.
4052946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     * @param year The initial year or 0 if no year has been specified
4062946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     * @param monthOfYear The initial month.
4072946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     * @param dayOfMonth The initial day of the month.
4082946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     * @param yearOptional True if the user can toggle the year
4092946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     * @param onDateChangedListener How user is notified date is changed by user, can be null.
4102946445b560fde5e63df17f5a2db60c8349fe532Romain Guy     */
4112946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    public void init(int year, int monthOfYear, int dayOfMonth, boolean yearOptional,
4122946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            OnDateChangedListener onDateChangedListener) {
4132946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYear = (yearOptional && year == 0) ? getCurrentYear() : year;
4142946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mMonth = monthOfYear;
4152946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mDay = dayOfMonth;
4162946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYearOptional = yearOptional;
4172946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mHasYear = !yearOptional || (year != 0);
4182946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mOnDateChangedListener = onDateChangedListener;
4192946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        updateSpinners();
4202946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
4212946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
4222946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private void updateSpinners() {
4232946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        updateDaySpinner();
4242946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYearToggle.setChecked(mHasYear);
4252946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYearToggle.setVisibility(mYearOptional ? View.VISIBLE : View.GONE);
4262946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYearPicker.setValue(mYear);
4272946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mYearPicker.setVisibility(mHasYear ? View.VISIBLE : View.GONE);
4282946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
4292946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        /* The month display uses 1-12 but our internal state stores it
4302946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         * 0-11 so add one when setting the display.
4312946445b560fde5e63df17f5a2db60c8349fe532Romain Guy         */
4322946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mMonthPicker.setValue(mMonth + 1);
4332946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
4342946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
4352946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private void updateDaySpinner() {
4362946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        Calendar cal = Calendar.getInstance();
4372946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        // if year was not set, use 2000 as it was a leap year
4382946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        cal.set(mHasYear ? mYear : 2000, mMonth, 1);
4392946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        int max = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
4402946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mDayPicker.setMinValue(1);
4412946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mDayPicker.setMaxValue(max);
4422946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        mDayPicker.setValue(mDay);
4432946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
4442946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
4452946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    public int getYear() {
4462946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        return (mYearOptional && !mHasYear) ? 0 : mYear;
4472946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
4482946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
4492946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    public int getMonth() {
4502946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        return mMonth;
4512946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
4522946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
4532946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    public int getDayOfMonth() {
4542946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        return mDay;
4552946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
4562946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
4572946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private void adjustMaxDay(){
4582946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        Calendar cal = Calendar.getInstance();
4592946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        // if year was not set, use 2000 as it was a leap year
4602946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        cal.set(Calendar.YEAR, mHasYear ? mYear : 2000);
4612946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        cal.set(Calendar.MONTH, mMonth);
4622946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        int max = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
4632946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        if (mDay > max) {
4642946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mDay = max;
4652946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
4662946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
4672946445b560fde5e63df17f5a2db60c8349fe532Romain Guy
4682946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    private void notifyDateChanged() {
4692946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        if (mOnDateChangedListener != null) {
4702946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            int year = (mYearOptional && !mHasYear) ? 0 : mYear;
4712946445b560fde5e63df17f5a2db60c8349fe532Romain Guy            mOnDateChangedListener.onDateChanged(DatePicker.this, year, mMonth, mDay);
4722946445b560fde5e63df17f5a2db60c8349fe532Romain Guy        }
4732946445b560fde5e63df17f5a2db60c8349fe532Romain Guy    }
4742946445b560fde5e63df17f5a2db60c8349fe532Romain Guy}
475