DatePicker.java revision 3fec3fe0e3a83c5e0d1264f34bcc55b158537bc6
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
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.annotation.Widget;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
21f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganovimport android.content.res.Configuration;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcelable;
25e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport android.text.TextUtils;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.format.DateFormat;
27dddda8d188408ff18935b1b0e15a00fe012a03daKenny Rootimport android.text.format.DateUtils;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
29e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport android.util.Log;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.SparseArray;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.LayoutInflater;
328a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
333fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganovimport android.view.accessibility.AccessibilityManager;
34cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganovimport android.widget.NumberPicker.OnValueChangeListener;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganovimport com.android.internal.R;
37f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
38e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport java.text.ParseException;
3903a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischerimport java.text.SimpleDateFormat;
40156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganovimport java.util.Arrays;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Calendar;
42dddda8d188408ff18935b1b0e15a00fe012a03daKenny Rootimport java.util.Locale;
43e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport java.util.TimeZone;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
46e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * This class is a widget for selecting a date. The date can be selected by a
47e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * year, month, and day spinners or a {@link CalendarView}. The set of spinners
48e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * and the calendar view are automatically synchronized. The client can
49e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * customize whether only the spinners, or only the calendar view, or both to be
50e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * displayed. Also the minimal and maximal date from which dates to be selected
51e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * can be customized.
5250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * <p>
539a143e6641fa4a5942e7341007d916601402e8dfDirk Dougherty * See the <a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Date
549a143e6641fa4a5942e7341007d916601402e8dfDirk Dougherty * Picker tutorial</a>.
5550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * </p>
56e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p>
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For a dialog using this view, see {@link android.app.DatePickerDialog}.
58e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p>
59e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov *
60e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_startYear
61e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_endYear
62e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_maxDate
63e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_minDate
64e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_spinnersShown
65e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_calendarViewShown
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project@Widget
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class DatePicker extends FrameLayout {
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
70e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private static final String LOG_TAG = DatePicker.class.getSimpleName();
71e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
72e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private static final String DATE_FORMAT = "MM/dd/yyyy";
73e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DEFAULT_START_YEAR = 1900;
75dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root
7650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    private static final int DEFAULT_END_YEAR = 2100;
77dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root
78e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private static final boolean DEFAULT_CALENDAR_VIEW_SHOWN = true;
79e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
80e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private static final boolean DEFAULT_SPINNERS_SHOWN = true;
8150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
8225f84f323c607bbd9133432fd789ba29b2dcd4d4Svetoslav Ganov    private static final boolean DEFAULT_ENABLED_STATE = true;
8325f84f323c607bbd9133432fd789ba29b2dcd4d4Svetoslav Ganov
84e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final NumberPicker mDaySpinner;
8550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
86e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final LinearLayout mSpinners;
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
88e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final NumberPicker mMonthSpinner;
89e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
90e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final NumberPicker mYearSpinner;
91e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
92e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final CalendarView mCalendarView;
9350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
94f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private Locale mCurrentLocale;
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
96f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private OnDateChangedListener mOnDateChangedListener;
9750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
98f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private String[] mShortMonths;
9950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
100f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private final java.text.DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT);
10150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
102f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private int mNumberOfMonths;
103dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root
104f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private Calendar mTempDate;
105e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
106f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private Calendar mMinDate;
107e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
108f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private Calendar mMaxDate;
109e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
110f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private Calendar mCurrentDate;
111e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
11225f84f323c607bbd9133432fd789ba29b2dcd4d4Svetoslav Ganov    private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
11351c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
115e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * The callback used to indicate the user changes\d the date.
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public interface OnDateChangedListener {
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
120e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov         * Called upon a date change.
121e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov         *
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param view The view associated with this listener.
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param year The year that was set.
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param monthOfYear The month that was set (0-11) for compatibility
12550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         *            with {@link java.util.Calendar}.
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param dayOfMonth The day of the month that was set.
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth);
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public DatePicker(Context context) {
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(context, null);
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public DatePicker(Context context, AttributeSet attrs) {
1364243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        this(context, attrs, R.attr.datePickerStyle);
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public DatePicker(Context context, AttributeSet attrs, int defStyle) {
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super(context, attrs, defStyle);
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
142f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        // initialization based on locale
143f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        setCurrentLocale(Locale.getDefault());
144f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
1454243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        TypedArray attributesArray = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
1464243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                defStyle, 0);
147e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        boolean spinnersShown = attributesArray.getBoolean(R.styleable.DatePicker_spinnersShown,
148e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                DEFAULT_SPINNERS_SHOWN);
149e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        boolean calendarViewShown = attributesArray.getBoolean(
150e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                R.styleable.DatePicker_calendarViewShown, DEFAULT_CALENDAR_VIEW_SHOWN);
1514243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        int startYear = attributesArray.getInt(R.styleable.DatePicker_startYear,
1524243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                DEFAULT_START_YEAR);
153e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        int endYear = attributesArray.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
154e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        String minDate = attributesArray.getString(R.styleable.DatePicker_minDate);
155e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        String maxDate = attributesArray.getString(R.styleable.DatePicker_maxDate);
1564243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        int layoutResourceId = attributesArray.getResourceId(R.styleable.DatePicker_layout,
1574243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                R.layout.date_picker);
158e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        attributesArray.recycle();
159e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
16050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        LayoutInflater inflater = (LayoutInflater) context
16150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
1624243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        inflater.inflate(layoutResourceId, this, true);
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
164cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov        OnValueChangeListener onChangeListener = new OnValueChangeListener() {
165e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
166156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
167156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                // take care of wrapping of days and months to update greater fields
168156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                if (picker == mDaySpinner) {
169156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH);
170156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    if (oldVal == maxDayOfMonth && newVal == 1) {
171156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.DAY_OF_MONTH, 1);
172156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    } else if (oldVal == 1 && newVal == maxDayOfMonth) {
173156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.DAY_OF_MONTH, -1);
174156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    } else {
175156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.DAY_OF_MONTH, newVal - oldVal);
176156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    }
177156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                } else if (picker == mMonthSpinner) {
178156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    if (oldVal == 11 && newVal == 0) {
179156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.MONTH, 1);
180156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    } else if (oldVal == 0 && newVal == 11) {
181156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.MONTH, -1);
182156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    } else {
183156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.MONTH, newVal - oldVal);
184156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    }
185156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                } else if (picker == mYearSpinner) {
186156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    mTempDate.set(Calendar.YEAR, newVal);
187156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                } else {
188156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    throw new IllegalArgumentException();
189156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                }
190156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                // now set the date to the adjusted one
191156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                setDate(mTempDate.get(Calendar.YEAR), mTempDate.get(Calendar.MONTH),
192156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.get(Calendar.DAY_OF_MONTH));
19358f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov                updateSpinners();
19458f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov                updateCalendarView();
195156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                notifyDateChanged();
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        };
1985fe1e6221ea3bab3120f5b9c0ceacaf59d116c05Eric Fischer
199e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mSpinners = (LinearLayout) findViewById(R.id.pickers);
200e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
201e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        // calendar view day-picker
202e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView = (CalendarView) findViewById(R.id.calendar_view);
203e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView.setOnDateChangeListener(new CalendarView.OnDateChangeListener() {
204e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            public void onSelectedDayChange(CalendarView view, int year, int month, int monthDay) {
205156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                setDate(year, month, monthDay);
20658f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov                updateSpinners();
207156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                notifyDateChanged();
20828104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov            }
20928104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov        });
21028104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov
21150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        // day
212e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mDaySpinner = (NumberPicker) findViewById(R.id.day);
213e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mDaySpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
214e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mDaySpinner.setOnLongPressUpdateInterval(100);
215e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mDaySpinner.setOnValueChangedListener(onChangeListener);
2165fe1e6221ea3bab3120f5b9c0ceacaf59d116c05Eric Fischer
21750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        // month
218e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner = (NumberPicker) findViewById(R.id.month);
219e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setMinValue(0);
220e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setMaxValue(mNumberOfMonths - 1);
221f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mMonthSpinner.setDisplayedValues(mShortMonths);
222e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setOnLongPressUpdateInterval(200);
223e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setOnValueChangedListener(onChangeListener);
22450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
22550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        // year
226e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mYearSpinner = (NumberPicker) findViewById(R.id.year);
227e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mYearSpinner.setOnLongPressUpdateInterval(100);
228e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mYearSpinner.setOnValueChangedListener(onChangeListener);
229e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
230e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        // show only what the user required but make sure we
231e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        // show something and the spinners have higher priority
232e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        if (!spinnersShown && !calendarViewShown) {
233e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            setSpinnersShown(true);
234e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        } else {
235e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            setSpinnersShown(spinnersShown);
236e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            setCalendarViewShown(calendarViewShown);
23713427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        }
238e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
23913427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        // set the min date giving priority of the minDate over startYear
24013427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        mTempDate.clear();
24113427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        if (!TextUtils.isEmpty(minDate)) {
24213427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov            if (!parseDate(minDate, mTempDate)) {
243e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                mTempDate.set(startYear, 0, 1);
244e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            }
24513427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        } else {
24613427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov            mTempDate.set(startYear, 0, 1);
24713427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        }
24813427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        setMinDate(mTempDate.getTimeInMillis());
24913427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov
25013427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        // set the max date giving priority of the maxDate over endYear
25113427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        mTempDate.clear();
25213427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        if (!TextUtils.isEmpty(maxDate)) {
25313427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov            if (!parseDate(maxDate, mTempDate)) {
254e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                mTempDate.set(endYear, 11, 31);
255e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            }
25613427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        } else {
25713427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov            mTempDate.set(endYear, 11, 31);
258e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        }
25913427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        setMaxDate(mTempDate.getTimeInMillis());
26013427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov
26113427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        // initialize to current date
26213427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        mCurrentDate.setTimeInMillis(System.currentTimeMillis());
26313427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        init(mCurrentDate.get(Calendar.YEAR), mCurrentDate.get(Calendar.MONTH), mCurrentDate
26413427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov                .get(Calendar.DAY_OF_MONTH), null);
265e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
266e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        // re-order the number spinners to match the current date format
267e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        reorderSpinners();
2683fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov
2693fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        // set content descriptions
2703fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
2713fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov            setContentDescriptions();
2723fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        }
273e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
274e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
275e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
276e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Gets the minimal date supported by this {@link DatePicker} in
277e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * milliseconds since January 1, 1970 00:00:00 in
278e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * {@link TimeZone#getDefault()} time zone.
279e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * <p>
280e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Note: The default minimal date is 01/01/1900.
281e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * <p>
282e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
283e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @return The minimal supported date.
284e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
285e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public long getMinDate() {
286e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        return mCalendarView.getMinDate();
287e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
288e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
289e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
290e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Sets the minimal date supported by this {@link NumberPicker} in
291e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * milliseconds since January 1, 1970 00:00:00 in
292e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * {@link TimeZone#getDefault()} time zone.
293e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
294e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @param minDate The minimal supported date.
295e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
296e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public void setMinDate(long minDate) {
297e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mTempDate.setTimeInMillis(minDate);
298e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR)
299e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMinDate.get(Calendar.DAY_OF_YEAR)) {
300e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            return;
301e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        }
302e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMinDate.setTimeInMillis(minDate);
303e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView.setMinDate(minDate);
304156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        if (mCurrentDate.before(mMinDate)) {
305156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
306156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            updateCalendarView();
307156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        }
308156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        updateSpinners();
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
31050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
31128104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov    /**
312e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Gets the maximal date supported by this {@link DatePicker} in
313e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * milliseconds since January 1, 1970 00:00:00 in
314e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * {@link TimeZone#getDefault()} time zone.
315e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * <p>
316e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Note: The default maximal date is 12/31/2100.
31728104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov     * <p>
31828104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov     *
319e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @return The maximal supported date.
320e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
321e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public long getMaxDate() {
322e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        return mCalendarView.getMaxDate();
323e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
324e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
325e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
326e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Sets the maximal date supported by this {@link DatePicker} in
327e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * milliseconds since January 1, 1970 00:00:00 in
328e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * {@link TimeZone#getDefault()} time zone.
329e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
330e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @param maxDate The maximal supported date.
33128104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov     */
332e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public void setMaxDate(long maxDate) {
333e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mTempDate.setTimeInMillis(maxDate);
334e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)
335e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate.get(Calendar.DAY_OF_YEAR)) {
336e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            return;
33728104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov        }
338e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMaxDate.setTimeInMillis(maxDate);
339e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView.setMaxDate(maxDate);
340156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        if (mCurrentDate.after(mMaxDate)) {
341156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
342156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            updateCalendarView();
343156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        }
344156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        updateSpinners();
34528104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov    }
34628104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setEnabled(boolean enabled) {
34951c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        if (mIsEnabled == enabled) {
35051c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov            return;
35151c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        }
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.setEnabled(enabled);
353e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mDaySpinner.setEnabled(enabled);
354e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setEnabled(enabled);
355e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mYearSpinner.setEnabled(enabled);
356e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView.setEnabled(enabled);
35751c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        mIsEnabled = enabled;
35851c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov    }
35951c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov
36051c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov    @Override
36151c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov    public boolean isEnabled() {
36251c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        return mIsEnabled;
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3658a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov    @Override
3663fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
3673fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        onPopulateAccessibilityEvent(event);
3683fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        return true;
3693fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov    }
3703fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov
3713fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov    @Override
372736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
373736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov        super.onPopulateAccessibilityEvent(event);
374736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov
3753fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
3768a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        String selectedDateUtterance = DateUtils.formatDateTime(mContext,
3778a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov                mCurrentDate.getTimeInMillis(), flags);
3788a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        event.getText().add(selectedDateUtterance);
3798a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov    }
3808a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov
381f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    @Override
382f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    protected void onConfigurationChanged(Configuration newConfig) {
383f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        super.onConfigurationChanged(newConfig);
384f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        setCurrentLocale(newConfig.locale);
385f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    }
386f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
38750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
388e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Gets whether the {@link CalendarView} is shown.
389e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
390e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @return True if the calendar view is shown.
3915f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov     * @see #getCalendarView()
392e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
393e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public boolean getCalendarViewShown() {
394e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        return mCalendarView.isShown();
395e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
396e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
397e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
3985f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov     * Gets the {@link CalendarView}.
3995f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov     *
4005f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov     * @return The calendar view.
4015f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov     * @see #getCalendarViewShown()
4025f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov     */
4035f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov    public CalendarView getCalendarView () {
4045f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov        return mCalendarView;
4055f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov    }
4065f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov
4075f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov    /**
408e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Sets whether the {@link CalendarView} is shown.
409e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
410e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @param shown True if the calendar view is to be shown.
411e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
412e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public void setCalendarViewShown(boolean shown) {
413e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView.setVisibility(shown ? VISIBLE : GONE);
414e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
415e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
416e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
417e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Gets whether the spinners are shown.
418e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
419e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @return True if the spinners are shown.
42050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
421e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public boolean getSpinnersShown() {
422e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        return mSpinners.isShown();
423e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
424e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
425e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
426e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Sets whether the spinners are shown.
427e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
428e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @param shown True if the spinners are to be shown.
429e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
430e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public void setSpinnersShown(boolean shown) {
431e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mSpinners.setVisibility(shown ? VISIBLE : GONE);
432e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
433e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
434e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
435f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     * Sets the current locale.
436f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     *
437f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     * @param locale The current locale.
438f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     */
439f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private void setCurrentLocale(Locale locale) {
440f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        if (locale.equals(mCurrentLocale)) {
441f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov            return;
442f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        }
443f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
444f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mCurrentLocale = locale;
445f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
446f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mTempDate = getCalendarForLocale(mTempDate, locale);
447f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mMinDate = getCalendarForLocale(mMinDate, locale);
448f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mMaxDate = getCalendarForLocale(mMaxDate, locale);
449f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mCurrentDate = getCalendarForLocale(mCurrentDate, locale);
450f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
451f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1;
452f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mShortMonths = new String[mNumberOfMonths];
453f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        for (int i = 0; i < mNumberOfMonths; i++) {
454f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov            mShortMonths[i] = DateUtils.getMonthString(Calendar.JANUARY + i,
455f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov                    DateUtils.LENGTH_MEDIUM);
456f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        }
457f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    }
458f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
459f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    /**
460f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     * Gets a calendar for locale bootstrapped with the value of a given calendar.
461f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     *
462f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     * @param oldCalendar The old calendar.
463f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     * @param locale The locale.
464f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     */
465f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
466f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        if (oldCalendar == null) {
467f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov            return Calendar.getInstance(locale);
468f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        } else {
469f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov            final long currentTimeMillis = oldCalendar.getTimeInMillis();
470f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov            Calendar newCalendar = Calendar.getInstance(locale);
471f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov            newCalendar.setTimeInMillis(currentTimeMillis);
472f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov            return newCalendar;
473f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        }
474f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    }
475f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
476f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    /**
477f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov     * Reorders the spinners according to the date format that is
478f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov     * explicitly set by the user and if no such is set fall back
479f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov     * to the current locale's default format.
480e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
481e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private void reorderSpinners() {
482f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov        mSpinners.removeAllViews();
483f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov        char[] order = DateFormat.getDateFormatOrder(getContext());
484f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov        for (int i = 0; i < order.length; i++) {
485f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov            switch (order[i]) {
486f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                case DateFormat.DATE:
487f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                    mSpinners.addView(mDaySpinner);
488f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                    break;
489f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                case DateFormat.MONTH:
490f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                    mSpinners.addView(mMonthSpinner);
491f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                    break;
492f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                case DateFormat.YEAR:
493f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                    mSpinners.addView(mYearSpinner);
494f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                    break;
495f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                default:
496f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                    throw new IllegalArgumentException();
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
50150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
50250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * Updates the current date.
50350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     *
50450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @param year The year.
50550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @param month The month which is <strong>starting from zero</strong>.
50650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @param dayOfMonth The day of the month.
50750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
50850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    public void updateDate(int year, int month, int dayOfMonth) {
509156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        if (!isNewDate(year, month, dayOfMonth)) {
510156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            return;
511dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root        }
512156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        setDate(year, month, dayOfMonth);
51358f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateSpinners();
51458f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateCalendarView();
515156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        notifyDateChanged();
516dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root    }
517dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root
51850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    // Override so we are in complete control of save / restore for this widget.
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        dispatchThawSelfOnly(container);
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected Parcelable onSaveInstanceState() {
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Parcelable superState = super.onSaveInstanceState();
527156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        return new SavedState(superState, getYear(), getMonth(), getDayOfMonth());
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onRestoreInstanceState(Parcelable state) {
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SavedState ss = (SavedState) state;
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onRestoreInstanceState(ss.getSuperState());
534156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        setDate(ss.mYear, ss.mMonth, ss.mDay);
53558f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateSpinners();
53658f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateCalendarView();
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
54050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * Initialize the state. If the provided values designate an inconsistent
541e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * date the values are normalized before updating the spinners.
54250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     *
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param year The initial year.
54450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @param monthOfYear The initial month <strong>starting from zero</strong>.
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param dayOfMonth The initial day of the month.
54650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @param onDateChangedListener How user is notified date is changed by
54750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     *            user, can be null.
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void init(int year, int monthOfYear, int dayOfMonth,
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            OnDateChangedListener onDateChangedListener) {
551156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        setDate(year, monthOfYear, dayOfMonth);
55258f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateSpinners();
55358f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateCalendarView();
5542f136a874d240cc7e85e8de9c7644a7daa9532daSvetoslav Ganov        mOnDateChangedListener = onDateChangedListener;
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
55750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
558e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Parses the given <code>date</code> and in case of success sets the result
559e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * to the <code>outDate</code>.
560a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov     *
561e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @return True if the date was parsed.
562a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov     */
563e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private boolean parseDate(String date, Calendar outDate) {
564e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        try {
565e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            outDate.setTime(mDateFormat.parse(date));
566e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            return true;
567e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        } catch (ParseException e) {
568e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT);
569e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            return false;
570e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        }
571a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov    }
572a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov
573156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov    private boolean isNewDate(int year, int month, int dayOfMonth) {
574156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        return (mCurrentDate.get(Calendar.YEAR) != year
575156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                || mCurrentDate.get(Calendar.MONTH) != dayOfMonth
576156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                || mCurrentDate.get(Calendar.DAY_OF_MONTH) != month);
577156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov    }
578e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
579156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov    private void setDate(int year, int month, int dayOfMonth) {
580156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mCurrentDate.set(year, month, dayOfMonth);
581e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        if (mCurrentDate.before(mMinDate)) {
582e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
583e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        } else if (mCurrentDate.after(mMaxDate)) {
584e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
585e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        }
586e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
587e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
588156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov    private void updateSpinners() {
589156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        // set the spinner ranges respecting the min and max dates
590156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        if (mCurrentDate.equals(mMinDate)) {
591156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMinValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
592156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
593156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setWrapSelectorWheel(false);
594156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setDisplayedValues(null);
595156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMinValue(mCurrentDate.get(Calendar.MONTH));
596156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.MONTH));
597156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setWrapSelectorWheel(false);
598156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        } else if (mCurrentDate.equals(mMaxDate)) {
599156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.DAY_OF_MONTH));
600156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMaxValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
601156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setWrapSelectorWheel(false);
602156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setDisplayedValues(null);
603156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.MONTH));
604156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMaxValue(mCurrentDate.get(Calendar.MONTH));
605156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setWrapSelectorWheel(false);
606156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        } else {
607156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMinValue(1);
608156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
609156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setWrapSelectorWheel(true);
610156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setDisplayedValues(null);
611156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMinValue(0);
612156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMaxValue(11);
613156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setWrapSelectorWheel(true);
614e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        }
615e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
616156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        // make sure the month names are a zero based array
617156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        // with the months in the month spinner
618f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        String[] displayedValues = Arrays.copyOfRange(mShortMonths,
619156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1);
620156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mMonthSpinner.setDisplayedValues(displayedValues);
621156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov
622156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        // year spinner range does not change based on the current date
623156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR));
624156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR));
625156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mYearSpinner.setWrapSelectorWheel(false);
626156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov
627156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        // set the spinner values
628156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR));
629156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH));
630156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
63350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
634156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov     * Updates the calendar view with the current date.
63550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
636e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private void updateCalendarView() {
637156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov         mCalendarView.setDate(mCurrentDate.getTimeInMillis(), false, false);
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
64050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
64150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @return The selected year.
64250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getYear() {
644156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        return mCurrentDate.get(Calendar.YEAR);
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
64750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
64850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @return The selected month.
64950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getMonth() {
651156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        return mCurrentDate.get(Calendar.MONTH);
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
65450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
65550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @return The selected day of month.
65650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getDayOfMonth() {
658156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        return mCurrentDate.get(Calendar.DAY_OF_MONTH);
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6602bf761c20253222a763bce9a63d14c48ab08a556Suchi Amalapurapu
66150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
66250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * Notifies the listener, if such, for a change in the selected date.
66350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
66450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    private void notifyDateChanged() {
6658a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
66650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        if (mOnDateChangedListener != null) {
667156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mOnDateChangedListener.onDateChanged(this, getYear(), getMonth(), getDayOfMonth());
6682bf761c20253222a763bce9a63d14c48ab08a556Suchi Amalapurapu        }
6692bf761c20253222a763bce9a63d14c48ab08a556Suchi Amalapurapu    }
670e3491b6b5f1d3fb871074766597b275d9f682faaKenneth Andersson
67150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
67250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * Class for managing state storing/restoring.
67350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
67450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    private static class SavedState extends BaseSavedState {
67550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
67650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        private final int mYear;
67750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
67850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        private final int mMonth;
67950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
68050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        private final int mDay;
68150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
68250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        /**
68350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         * Constructor called from {@link DatePicker#onSaveInstanceState()}
68450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         */
68550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        private SavedState(Parcelable superState, int year, int month, int day) {
68650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            super(superState);
68750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mYear = year;
68850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mMonth = month;
68950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mDay = day;
69050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        }
69150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
69250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        /**
69350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         * Constructor called from {@link #CREATOR}
69450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         */
69550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        private SavedState(Parcel in) {
69650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            super(in);
69750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mYear = in.readInt();
69850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mMonth = in.readInt();
69950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mDay = in.readInt();
700e3491b6b5f1d3fb871074766597b275d9f682faaKenneth Andersson        }
70150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
70250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        @Override
70350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        public void writeToParcel(Parcel dest, int flags) {
70450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            super.writeToParcel(dest, flags);
70550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            dest.writeInt(mYear);
70650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            dest.writeInt(mMonth);
70750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            dest.writeInt(mDay);
70850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        }
70950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
71050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        @SuppressWarnings("all")
71150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        // suppress unused and hiding
71250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
71350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
71450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            public SavedState createFromParcel(Parcel in) {
71550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov                return new SavedState(in);
71650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            }
71750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
71850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            public SavedState[] newArray(int size) {
71950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov                return new SavedState[size];
72050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            }
72150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        };
722e3491b6b5f1d3fb871074766597b275d9f682faaKenneth Andersson    }
723f114809031c5e5017bf69ab7a6d01024f1745fc8Svetoslav Ganov
7243fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov    private void setContentDescriptions() {
7253fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        // Day
7263fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        String text = mContext.getString(R.string.date_picker_increment_day_button);
7273fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        mDaySpinner.findViewById(R.id.increment).setContentDescription(text);
7283fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        text = mContext.getString(R.string.date_picker_decrement_day_button);
7293fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        mDaySpinner.findViewById(R.id.decrement).setContentDescription(text);
7303fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        // Month
7313fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        text = mContext.getString(R.string.date_picker_increment_month_button);
7323fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        mMonthSpinner.findViewById(R.id.increment).setContentDescription(text);
7333fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        text = mContext.getString(R.string.date_picker_decrement_month_button);
7343fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        mMonthSpinner.findViewById(R.id.decrement).setContentDescription(text);
7353fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        // Year
7363fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        text = mContext.getString(R.string.date_picker_increment_year_button);
7373fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        mYearSpinner.findViewById(R.id.increment).setContentDescription(text);
7383fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        text = mContext.getString(R.string.date_picker_decrement_year_button);
7393fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        mYearSpinner.findViewById(R.id.decrement).setContentDescription(text);
7403fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov    }
7413fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov}
742