DatePicker.java revision 8a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.widget;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport com.android.internal.R;
2050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.annotation.Widget;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcelable;
26e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport android.text.TextUtils;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.format.DateFormat;
28dddda8d188408ff18935b1b0e15a00fe012a03daKenny Rootimport android.text.format.DateUtils;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
30e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport android.util.Log;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.SparseArray;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.LayoutInflater;
338a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
34cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganovimport android.widget.NumberPicker.OnValueChangeListener;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport java.text.ParseException;
3703a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischerimport java.text.SimpleDateFormat;
38156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganovimport java.util.Arrays;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Calendar;
40dddda8d188408ff18935b1b0e15a00fe012a03daKenny Rootimport java.util.Locale;
41e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport java.util.TimeZone;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
44e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * This class is a widget for selecting a date. The date can be selected by a
45e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * year, month, and day spinners or a {@link CalendarView}. The set of spinners
46e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * and the calendar view are automatically synchronized. The client can
47e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * customize whether only the spinners, or only the calendar view, or both to be
48e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * displayed. Also the minimal and maximal date from which dates to be selected
49e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * can be customized.
5050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * <p>
519a143e6641fa4a5942e7341007d916601402e8dfDirk Dougherty * See the <a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Date
529a143e6641fa4a5942e7341007d916601402e8dfDirk Dougherty * Picker tutorial</a>.
5350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * </p>
54e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p>
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For a dialog using this view, see {@link android.app.DatePickerDialog}.
56e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p>
57e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov *
58e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_startYear
59e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_endYear
60e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_maxDate
61e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_minDate
62e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_spinnersShown
63e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_calendarViewShown
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project@Widget
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class DatePicker extends FrameLayout {
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
68e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private static final String LOG_TAG = DatePicker.class.getSimpleName();
69e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
70e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private static final String DATE_FORMAT = "MM/dd/yyyy";
71e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DEFAULT_START_YEAR = 1900;
73dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root
7450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    private static final int DEFAULT_END_YEAR = 2100;
75dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root
76e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private static final boolean DEFAULT_CALENDAR_VIEW_SHOWN = true;
77e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
78e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private static final boolean DEFAULT_SPINNERS_SHOWN = true;
7950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
8025f84f323c607bbd9133432fd789ba29b2dcd4d4Svetoslav Ganov    private static final boolean DEFAULT_ENABLED_STATE = true;
8125f84f323c607bbd9133432fd789ba29b2dcd4d4Svetoslav Ganov
82e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final NumberPicker mDaySpinner;
8350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
84e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final LinearLayout mSpinners;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
86e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final NumberPicker mMonthSpinner;
87e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
88e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final NumberPicker mYearSpinner;
89e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
90e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final CalendarView mCalendarView;
9150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private OnDateChangedListener mOnDateChangedListener;
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    private Locale mMonthLocale;
9550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
96e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final Calendar mTempDate = Calendar.getInstance();
9750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
98e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final int mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1;
9950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
10050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    private final String[] mShortMonths = new String[mNumberOfMonths];
101dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root
102e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final java.text.DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT);
103e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
104e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final Calendar mMinDate = Calendar.getInstance();
105e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
106e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final Calendar mMaxDate = Calendar.getInstance();
107e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
108e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final Calendar mCurrentDate = Calendar.getInstance();
109e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
11025f84f323c607bbd9133432fd789ba29b2dcd4d4Svetoslav Ganov    private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
11151c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
113e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * The callback used to indicate the user changes\d the date.
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public interface OnDateChangedListener {
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
118e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov         * Called upon a date change.
119e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov         *
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param view The view associated with this listener.
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param year The year that was set.
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param monthOfYear The month that was set (0-11) for compatibility
12350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         *            with {@link java.util.Calendar}.
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param dayOfMonth The day of the month that was set.
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth);
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public DatePicker(Context context) {
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(context, null);
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public DatePicker(Context context, AttributeSet attrs) {
1344243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        this(context, attrs, R.attr.datePickerStyle);
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public DatePicker(Context context, AttributeSet attrs, int defStyle) {
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super(context, attrs, defStyle);
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1404243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        TypedArray attributesArray = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
1414243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                defStyle, 0);
142e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        boolean spinnersShown = attributesArray.getBoolean(R.styleable.DatePicker_spinnersShown,
143e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                DEFAULT_SPINNERS_SHOWN);
144e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        boolean calendarViewShown = attributesArray.getBoolean(
145e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                R.styleable.DatePicker_calendarViewShown, DEFAULT_CALENDAR_VIEW_SHOWN);
1464243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        int startYear = attributesArray.getInt(R.styleable.DatePicker_startYear,
1474243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                DEFAULT_START_YEAR);
148e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        int endYear = attributesArray.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
149e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        String minDate = attributesArray.getString(R.styleable.DatePicker_minDate);
150e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        String maxDate = attributesArray.getString(R.styleable.DatePicker_maxDate);
1514243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        int layoutResourceId = attributesArray.getResourceId(R.styleable.DatePicker_layout,
1524243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                R.layout.date_picker);
153e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        attributesArray.recycle();
154e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
15550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        LayoutInflater inflater = (LayoutInflater) context
15650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
1574243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        inflater.inflate(layoutResourceId, this, true);
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
159cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov        OnValueChangeListener onChangeListener = new OnValueChangeListener() {
160e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
161156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
162156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                // take care of wrapping of days and months to update greater fields
163156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                if (picker == mDaySpinner) {
164156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH);
165156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    if (oldVal == maxDayOfMonth && newVal == 1) {
166156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.DAY_OF_MONTH, 1);
167156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    } else if (oldVal == 1 && newVal == maxDayOfMonth) {
168156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.DAY_OF_MONTH, -1);
169156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    } else {
170156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.DAY_OF_MONTH, newVal - oldVal);
171156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    }
172156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                } else if (picker == mMonthSpinner) {
173156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    if (oldVal == 11 && newVal == 0) {
174156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.MONTH, 1);
175156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    } else if (oldVal == 0 && newVal == 11) {
176156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.MONTH, -1);
177156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    } else {
178156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.MONTH, newVal - oldVal);
179156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    }
180156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                } else if (picker == mYearSpinner) {
181156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    mTempDate.set(Calendar.YEAR, newVal);
182156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                } else {
183156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    throw new IllegalArgumentException();
184156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                }
185156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                // now set the date to the adjusted one
186156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                setDate(mTempDate.get(Calendar.YEAR), mTempDate.get(Calendar.MONTH),
187156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.get(Calendar.DAY_OF_MONTH));
18858f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov                updateSpinners();
18958f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov                updateCalendarView();
190156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                notifyDateChanged();
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        };
1935fe1e6221ea3bab3120f5b9c0ceacaf59d116c05Eric Fischer
194e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mSpinners = (LinearLayout) findViewById(R.id.pickers);
195e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
196e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        // calendar view day-picker
197e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView = (CalendarView) findViewById(R.id.calendar_view);
198e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView.setOnDateChangeListener(new CalendarView.OnDateChangeListener() {
199e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            public void onSelectedDayChange(CalendarView view, int year, int month, int monthDay) {
200156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                setDate(year, month, monthDay);
20158f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov                updateSpinners();
202156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                notifyDateChanged();
20328104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov            }
20428104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov        });
20528104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov
20650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        // day
207e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mDaySpinner = (NumberPicker) findViewById(R.id.day);
208e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mDaySpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
209e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mDaySpinner.setOnLongPressUpdateInterval(100);
210e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mDaySpinner.setOnValueChangedListener(onChangeListener);
2115fe1e6221ea3bab3120f5b9c0ceacaf59d116c05Eric Fischer
21250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        // month
213e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner = (NumberPicker) findViewById(R.id.month);
214e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setMinValue(0);
215e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setMaxValue(mNumberOfMonths - 1);
216e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setDisplayedValues(getShortMonths());
217e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setOnLongPressUpdateInterval(200);
218e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setOnValueChangedListener(onChangeListener);
21950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
22050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        // year
221e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mYearSpinner = (NumberPicker) findViewById(R.id.year);
222e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mYearSpinner.setOnLongPressUpdateInterval(100);
223e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mYearSpinner.setOnValueChangedListener(onChangeListener);
224e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
225e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        // show only what the user required but make sure we
226e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        // show something and the spinners have higher priority
227e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        if (!spinnersShown && !calendarViewShown) {
228e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            setSpinnersShown(true);
229e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        } else {
230e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            setSpinnersShown(spinnersShown);
231e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            setCalendarViewShown(calendarViewShown);
232e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
233e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            // set the min date giving priority of the minDate over startYear
234e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mTempDate.clear();
235e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            if (!TextUtils.isEmpty(minDate)) {
236e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                if (!parseDate(minDate, mTempDate)) {
237e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                    mTempDate.set(startYear, 0, 1);
238e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                }
239e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            } else {
240e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                mTempDate.set(startYear, 0, 1);
241e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            }
242e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mMinDate.clear();
243e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            setMinDate(mTempDate.getTimeInMillis());
244e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
245e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            // set the max date giving priority of the minDate over startYear
246e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mTempDate.clear();
247e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            if (!TextUtils.isEmpty(maxDate)) {
248e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                if (!parseDate(maxDate, mTempDate)) {
249e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                    mTempDate.set(endYear, 11, 31);
250e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                }
251e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            } else {
252e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                mTempDate.set(endYear, 11, 31);
253e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            }
254e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mMaxDate.clear();
255e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            setMaxDate(mTempDate.getTimeInMillis());
256e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
257e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            // initialize to current date
258e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mCurrentDate.setTimeInMillis(System.currentTimeMillis());
259e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            init(mCurrentDate.get(Calendar.YEAR), mCurrentDate.get(Calendar.MONTH), mCurrentDate
260e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                    .get(Calendar.DAY_OF_MONTH), null);
261e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        }
262e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
263e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        // re-order the number spinners to match the current date format
264e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        reorderSpinners();
265e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
266e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
267e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
268e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Gets the minimal date supported by this {@link DatePicker} in
269e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * milliseconds since January 1, 1970 00:00:00 in
270e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * {@link TimeZone#getDefault()} time zone.
271e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * <p>
272e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Note: The default minimal date is 01/01/1900.
273e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * <p>
274e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
275e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @return The minimal supported date.
276e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
277e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public long getMinDate() {
278e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        return mCalendarView.getMinDate();
279e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
280e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
281e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
282e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Sets the minimal date supported by this {@link NumberPicker} in
283e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * milliseconds since January 1, 1970 00:00:00 in
284e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * {@link TimeZone#getDefault()} time zone.
285e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
286e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @param minDate The minimal supported date.
287e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
288e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public void setMinDate(long minDate) {
289e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mTempDate.setTimeInMillis(minDate);
290e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR)
291e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMinDate.get(Calendar.DAY_OF_YEAR)) {
292e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            return;
293e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        }
294e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMinDate.setTimeInMillis(minDate);
295e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView.setMinDate(minDate);
296156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        if (mCurrentDate.before(mMinDate)) {
297156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
298156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            updateCalendarView();
299156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        }
300156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        updateSpinners();
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
30250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
30328104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov    /**
304e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Gets the maximal date supported by this {@link DatePicker} in
305e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * milliseconds since January 1, 1970 00:00:00 in
306e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * {@link TimeZone#getDefault()} time zone.
307e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * <p>
308e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Note: The default maximal date is 12/31/2100.
30928104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov     * <p>
31028104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov     *
311e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @return The maximal supported date.
312e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
313e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public long getMaxDate() {
314e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        return mCalendarView.getMaxDate();
315e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
316e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
317e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
318e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Sets the maximal date supported by this {@link DatePicker} in
319e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * milliseconds since January 1, 1970 00:00:00 in
320e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * {@link TimeZone#getDefault()} time zone.
321e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
322e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @param maxDate The maximal supported date.
32328104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov     */
324e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public void setMaxDate(long maxDate) {
325e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mTempDate.setTimeInMillis(maxDate);
326e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)
327e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate.get(Calendar.DAY_OF_YEAR)) {
328e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            return;
32928104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov        }
330e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMaxDate.setTimeInMillis(maxDate);
331e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView.setMaxDate(maxDate);
332156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        if (mCurrentDate.after(mMaxDate)) {
333156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
334156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            updateCalendarView();
335156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        }
336156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        updateSpinners();
33728104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov    }
33828104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setEnabled(boolean enabled) {
34151c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        if (mIsEnabled == enabled) {
34251c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov            return;
34351c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        }
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.setEnabled(enabled);
345e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mDaySpinner.setEnabled(enabled);
346e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setEnabled(enabled);
347e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mYearSpinner.setEnabled(enabled);
348e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView.setEnabled(enabled);
34951c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        mIsEnabled = enabled;
35051c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov    }
35151c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov
35251c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov    @Override
35351c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov    public boolean isEnabled() {
35451c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        return mIsEnabled;
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3578a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov    @Override
3588a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
3598a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY
3608a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov                | DateUtils.FORMAT_SHOW_YEAR;
3618a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        String selectedDateUtterance = DateUtils.formatDateTime(mContext,
3628a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov                mCurrentDate.getTimeInMillis(), flags);
3638a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        event.getText().add(selectedDateUtterance);
3648a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        return true;
3658a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov    }
3668a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov
36750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
368e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Gets whether the {@link CalendarView} is shown.
369e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
370e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @return True if the calendar view is shown.
371e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
372e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public boolean getCalendarViewShown() {
373e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        return mCalendarView.isShown();
374e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
375e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
376e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
377e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Sets whether the {@link CalendarView} is shown.
378e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
379e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @param shown True if the calendar view is to be shown.
380e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
381e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public void setCalendarViewShown(boolean shown) {
382e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView.setVisibility(shown ? VISIBLE : GONE);
383e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
384e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
385e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
386e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Gets whether the spinners are shown.
387e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
388e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @return True if the spinners are shown.
38950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
390e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public boolean getSpinnersShown() {
391e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        return mSpinners.isShown();
392e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
393e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
394e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
395e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Sets whether the spinners are shown.
396e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
397e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @param shown True if the spinners are to be shown.
398e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
399e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public void setSpinnersShown(boolean shown) {
400e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mSpinners.setVisibility(shown ? VISIBLE : GONE);
401e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
402e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
403e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
404e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Reorders the spinners according to the date format in the current
405e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * {@link Locale}.
406e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
407e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private void reorderSpinners() {
40803a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        java.text.DateFormat format;
40903a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        String order;
41003a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer
41103a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        /*
41250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         * If the user is in a locale where the medium date format is still
41350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         * numeric (Japanese and Czech, for example), respect the date format
41450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         * order setting. Otherwise, use the order that the locale says is
41550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         * appropriate for a spelled-out date.
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
41703a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer
41850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        if (getShortMonths()[0].startsWith("1")) {
41903a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer            format = DateFormat.getDateFormat(getContext());
42003a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        } else {
42103a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer            format = DateFormat.getMediumDateFormat(getContext());
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
42303a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer
42403a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        if (format instanceof SimpleDateFormat) {
42503a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer            order = ((SimpleDateFormat) format).toPattern();
42603a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        } else {
42703a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer            // Shouldn't happen, but just in case.
42803a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer            order = new String(DateFormat.getDateFormatOrder(getContext()));
42903a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        }
43003a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer
43150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        /*
432e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov         * Remove the 3 spinners from their parent and then add them back in the
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * required order.
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
435e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        LinearLayout parent = mSpinners;
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        parent.removeAllViews();
43703a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer
43803a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        boolean quoted = false;
43903a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        boolean didDay = false, didMonth = false, didYear = false;
44003a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer
44103a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        for (int i = 0; i < order.length(); i++) {
44203a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer            char c = order.charAt(i);
44303a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer
44403a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer            if (c == '\'') {
44503a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer                quoted = !quoted;
44603a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer            }
44703a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer
44803a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer            if (!quoted) {
44903a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer                if (c == DateFormat.DATE && !didDay) {
450e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                    parent.addView(mDaySpinner);
45103a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer                    didDay = true;
45203a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer                } else if ((c == DateFormat.MONTH || c == 'L') && !didMonth) {
453e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                    parent.addView(mMonthSpinner);
45403a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer                    didMonth = true;
45503a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer                } else if (c == DateFormat.YEAR && !didYear) {
456e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                    parent.addView(mYearSpinner);
45703a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer                    didYear = true;
45803a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer                }
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
46103a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer
46203a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        // Shouldn't happen, but just in case.
46303a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        if (!didMonth) {
464e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            parent.addView(mMonthSpinner);
46503a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        }
46603a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        if (!didDay) {
467e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            parent.addView(mDaySpinner);
46803a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        }
46903a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        if (!didYear) {
470e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            parent.addView(mYearSpinner);
47103a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer        }
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
47450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
47550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * Updates the current date.
47650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     *
47750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @param year The year.
47850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @param month The month which is <strong>starting from zero</strong>.
47950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @param dayOfMonth The day of the month.
48050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
48150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    public void updateDate(int year, int month, int dayOfMonth) {
482156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        if (!isNewDate(year, month, dayOfMonth)) {
483156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            return;
484dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root        }
485156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        setDate(year, month, dayOfMonth);
48658f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateSpinners();
48758f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateCalendarView();
488156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        notifyDateChanged();
489dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root    }
490dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root
49150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    // Override so we are in complete control of save / restore for this widget.
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        dispatchThawSelfOnly(container);
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected Parcelable onSaveInstanceState() {
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Parcelable superState = super.onSaveInstanceState();
500156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        return new SavedState(superState, getYear(), getMonth(), getDayOfMonth());
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onRestoreInstanceState(Parcelable state) {
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SavedState ss = (SavedState) state;
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onRestoreInstanceState(ss.getSuperState());
507156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        setDate(ss.mYear, ss.mMonth, ss.mDay);
50858f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateSpinners();
50958f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateCalendarView();
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
51350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * Initialize the state. If the provided values designate an inconsistent
514e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * date the values are normalized before updating the spinners.
51550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     *
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param year The initial year.
51750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @param monthOfYear The initial month <strong>starting from zero</strong>.
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param dayOfMonth The initial day of the month.
51950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @param onDateChangedListener How user is notified date is changed by
52050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     *            user, can be null.
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void init(int year, int monthOfYear, int dayOfMonth,
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            OnDateChangedListener onDateChangedListener) {
524156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        setDate(year, monthOfYear, dayOfMonth);
52558f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateSpinners();
52658f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateCalendarView();
5272f136a874d240cc7e85e8de9c7644a7daa9532daSvetoslav Ganov        mOnDateChangedListener = onDateChangedListener;
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
53050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
531e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Parses the given <code>date</code> and in case of success sets the result
532e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * to the <code>outDate</code>.
533a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov     *
534e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @return True if the date was parsed.
535a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov     */
536e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private boolean parseDate(String date, Calendar outDate) {
537e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        try {
538e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            outDate.setTime(mDateFormat.parse(date));
539e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            return true;
540e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        } catch (ParseException e) {
541e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT);
542e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            return false;
543e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        }
544a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov    }
545a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov
546a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov    /**
547a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov     * @return The short month abbreviations.
548a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov     */
549a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov    private String[] getShortMonths() {
550a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov        final Locale currentLocale = Locale.getDefault();
551a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov        if (currentLocale.equals(mMonthLocale)) {
552a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov            return mShortMonths;
553a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov        } else {
554a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov            for (int i = 0; i < mNumberOfMonths; i++) {
555a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov                mShortMonths[i] = DateUtils.getMonthString(Calendar.JANUARY + i,
556a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov                        DateUtils.LENGTH_MEDIUM);
557a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov            }
558a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov            mMonthLocale = currentLocale;
559a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov            return mShortMonths;
560a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov        }
561a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov    }
562a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov
563156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov    private boolean isNewDate(int year, int month, int dayOfMonth) {
564156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        return (mCurrentDate.get(Calendar.YEAR) != year
565156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                || mCurrentDate.get(Calendar.MONTH) != dayOfMonth
566156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                || mCurrentDate.get(Calendar.DAY_OF_MONTH) != month);
567156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov    }
568e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
569156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov    private void setDate(int year, int month, int dayOfMonth) {
570156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mCurrentDate.set(year, month, dayOfMonth);
571e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        if (mCurrentDate.before(mMinDate)) {
572e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
573e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        } else if (mCurrentDate.after(mMaxDate)) {
574e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
575e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        }
576e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
577e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
578156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov    private void updateSpinners() {
579156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        // set the spinner ranges respecting the min and max dates
580156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        if (mCurrentDate.equals(mMinDate)) {
581156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMinValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
582156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
583156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setWrapSelectorWheel(false);
584156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setDisplayedValues(null);
585156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMinValue(mCurrentDate.get(Calendar.MONTH));
586156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.MONTH));
587156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setWrapSelectorWheel(false);
588156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        } else if (mCurrentDate.equals(mMaxDate)) {
589156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.DAY_OF_MONTH));
590156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMaxValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
591156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setWrapSelectorWheel(false);
592156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setDisplayedValues(null);
593156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.MONTH));
594156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMaxValue(mCurrentDate.get(Calendar.MONTH));
595156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setWrapSelectorWheel(false);
596156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        } else {
597156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMinValue(1);
598156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
599156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setWrapSelectorWheel(true);
600156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setDisplayedValues(null);
601156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMinValue(0);
602156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMaxValue(11);
603156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setWrapSelectorWheel(true);
604e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        }
605e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
606156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        // make sure the month names are a zero based array
607156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        // with the months in the month spinner
608156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        String[] displayedValues = Arrays.copyOfRange(getShortMonths(),
609156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1);
610156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mMonthSpinner.setDisplayedValues(displayedValues);
611156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov
612156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        // year spinner range does not change based on the current date
613156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR));
614156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR));
615156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mYearSpinner.setWrapSelectorWheel(false);
616156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov
617156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        // set the spinner values
618156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR));
619156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH));
620156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
62350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
624156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov     * Updates the calendar view with the current date.
62550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
626e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private void updateCalendarView() {
627156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov         mCalendarView.setDate(mCurrentDate.getTimeInMillis(), false, false);
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
63050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
63150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @return The selected year.
63250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getYear() {
634156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        return mCurrentDate.get(Calendar.YEAR);
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
63750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
63850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @return The selected month.
63950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getMonth() {
641156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        return mCurrentDate.get(Calendar.MONTH);
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
64450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
64550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @return The selected day of month.
64650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getDayOfMonth() {
648156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        return mCurrentDate.get(Calendar.DAY_OF_MONTH);
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6502bf761c20253222a763bce9a63d14c48ab08a556Suchi Amalapurapu
65150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
65250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * Notifies the listener, if such, for a change in the selected date.
65350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
65450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    private void notifyDateChanged() {
6558a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
65650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        if (mOnDateChangedListener != null) {
657156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mOnDateChangedListener.onDateChanged(this, getYear(), getMonth(), getDayOfMonth());
6582bf761c20253222a763bce9a63d14c48ab08a556Suchi Amalapurapu        }
6592bf761c20253222a763bce9a63d14c48ab08a556Suchi Amalapurapu    }
660e3491b6b5f1d3fb871074766597b275d9f682faaKenneth Andersson
66150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
66250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * Class for managing state storing/restoring.
66350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
66450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    private static class SavedState extends BaseSavedState {
66550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
66650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        private final int mYear;
66750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
66850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        private final int mMonth;
66950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
67050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        private final int mDay;
67150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
67250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        /**
67350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         * Constructor called from {@link DatePicker#onSaveInstanceState()}
67450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         */
67550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        private SavedState(Parcelable superState, int year, int month, int day) {
67650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            super(superState);
67750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mYear = year;
67850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mMonth = month;
67950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mDay = day;
68050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        }
68150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
68250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        /**
68350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         * Constructor called from {@link #CREATOR}
68450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         */
68550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        private SavedState(Parcel in) {
68650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            super(in);
68750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mYear = in.readInt();
68850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mMonth = in.readInt();
68950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mDay = in.readInt();
690e3491b6b5f1d3fb871074766597b275d9f682faaKenneth Andersson        }
69150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
69250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        @Override
69350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        public void writeToParcel(Parcel dest, int flags) {
69450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            super.writeToParcel(dest, flags);
69550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            dest.writeInt(mYear);
69650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            dest.writeInt(mMonth);
69750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            dest.writeInt(mDay);
69850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        }
69950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
70050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        @SuppressWarnings("all")
70150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        // suppress unused and hiding
70250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
70350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
70450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            public SavedState createFromParcel(Parcel in) {
70550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov                return new SavedState(in);
70650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            }
70750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
70850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            public SavedState[] newArray(int size) {
70950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov                return new SavedState[size];
71050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            }
71150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        };
712e3491b6b5f1d3fb871074766597b275d9f682faaKenneth Andersson    }
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
714