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;
26e9a74a1a31f82391d44840aa17293021fcab6837Hyejin Kimimport android.text.InputType;
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;
33d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganovimport android.view.View;
348a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
358a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo;
36a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganovimport android.view.inputmethod.EditorInfo;
376304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganovimport android.view.inputmethod.InputMethodManager;
38cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganovimport android.widget.NumberPicker.OnValueChangeListener;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
40f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganovimport com.android.internal.R;
41f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
42949e9df25bccb736675f950591d3a286ae4052fcElliott Hughesimport java.text.DateFormatSymbols;
43e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport java.text.ParseException;
4403a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischerimport java.text.SimpleDateFormat;
45156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganovimport java.util.Arrays;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Calendar;
47dddda8d188408ff18935b1b0e15a00fe012a03daKenny Rootimport java.util.Locale;
48e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport java.util.TimeZone;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
50659f145278ffd85f934a435dbec47ead685caf59Elliott Hughesimport libcore.icu.ICU;
51659f145278ffd85f934a435dbec47ead685caf59Elliott Hughes
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
53e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * This class is a widget for selecting a date. The date can be selected by a
54e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * year, month, and day spinners or a {@link CalendarView}. The set of spinners
55e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * and the calendar view are automatically synchronized. The client can
56e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * customize whether only the spinners, or only the calendar view, or both to be
57e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * displayed. Also the minimal and maximal date from which dates to be selected
58e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * can be customized.
5950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * <p>
604c359b76f9a030f92a302ba74a528faa170bad4eScott Main * See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
614c359b76f9a030f92a302ba74a528faa170bad4eScott Main * guide.
6250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * </p>
63e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p>
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For a dialog using this view, see {@link android.app.DatePickerDialog}.
65e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p>
66e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov *
67e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_startYear
68e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_endYear
69e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_maxDate
70e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_minDate
71e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_spinnersShown
72e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#DatePicker_calendarViewShown
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project@Widget
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class DatePicker extends FrameLayout {
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
77e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private static final String LOG_TAG = DatePicker.class.getSimpleName();
78e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
79e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private static final String DATE_FORMAT = "MM/dd/yyyy";
80e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DEFAULT_START_YEAR = 1900;
82dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root
8350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    private static final int DEFAULT_END_YEAR = 2100;
84dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root
85e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private static final boolean DEFAULT_CALENDAR_VIEW_SHOWN = true;
86e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
87e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private static final boolean DEFAULT_SPINNERS_SHOWN = true;
8850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
8925f84f323c607bbd9133432fd789ba29b2dcd4d4Svetoslav Ganov    private static final boolean DEFAULT_ENABLED_STATE = true;
9025f84f323c607bbd9133432fd789ba29b2dcd4d4Svetoslav Ganov
91e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final LinearLayout mSpinners;
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
93a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov    private final NumberPicker mDaySpinner;
94a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov
95e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final NumberPicker mMonthSpinner;
96e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
97e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final NumberPicker mYearSpinner;
98e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
996304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov    private final EditText mDaySpinnerInput;
1006304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov
1016304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov    private final EditText mMonthSpinnerInput;
1026304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov
1036304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov    private final EditText mYearSpinnerInput;
1046304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov
105e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final CalendarView mCalendarView;
10650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
107f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private Locale mCurrentLocale;
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
109f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private OnDateChangedListener mOnDateChangedListener;
11050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
111f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private String[] mShortMonths;
11250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
113f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private final java.text.DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT);
11450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
115f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private int mNumberOfMonths;
116dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root
117f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private Calendar mTempDate;
118e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
119f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private Calendar mMinDate;
120e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
121f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private Calendar mMaxDate;
122e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
123f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private Calendar mCurrentDate;
124e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
12525f84f323c607bbd9133432fd789ba29b2dcd4d4Svetoslav Ganov    private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
12651c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
128e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * The callback used to indicate the user changes\d the date.
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public interface OnDateChangedListener {
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
133e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov         * Called upon a date change.
134e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov         *
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param view The view associated with this listener.
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param year The year that was set.
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param monthOfYear The month that was set (0-11) for compatibility
13850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         *            with {@link java.util.Calendar}.
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param dayOfMonth The day of the month that was set.
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth);
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public DatePicker(Context context) {
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(context, null);
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public DatePicker(Context context, AttributeSet attrs) {
1494243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        this(context, attrs, R.attr.datePickerStyle);
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public DatePicker(Context context, AttributeSet attrs, int defStyle) {
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super(context, attrs, defStyle);
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
155f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        // initialization based on locale
156f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        setCurrentLocale(Locale.getDefault());
157f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
1584243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        TypedArray attributesArray = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
1594243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                defStyle, 0);
160e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        boolean spinnersShown = attributesArray.getBoolean(R.styleable.DatePicker_spinnersShown,
161e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                DEFAULT_SPINNERS_SHOWN);
162e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        boolean calendarViewShown = attributesArray.getBoolean(
163e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                R.styleable.DatePicker_calendarViewShown, DEFAULT_CALENDAR_VIEW_SHOWN);
1644243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        int startYear = attributesArray.getInt(R.styleable.DatePicker_startYear,
1654243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                DEFAULT_START_YEAR);
166e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        int endYear = attributesArray.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
167e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        String minDate = attributesArray.getString(R.styleable.DatePicker_minDate);
168e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        String maxDate = attributesArray.getString(R.styleable.DatePicker_maxDate);
169c49a8be0d2aee5a3d1ff50015a0c0758b0988cfbSvetoslav Ganov        int layoutResourceId = attributesArray.getResourceId(R.styleable.DatePicker_internalLayout,
1704243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                R.layout.date_picker);
171e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        attributesArray.recycle();
172e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
17350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        LayoutInflater inflater = (LayoutInflater) context
17450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
1754243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        inflater.inflate(layoutResourceId, this, true);
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
177cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov        OnValueChangeListener onChangeListener = new OnValueChangeListener() {
178e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
1796304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                updateInputState();
180156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
181156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                // take care of wrapping of days and months to update greater fields
182156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                if (picker == mDaySpinner) {
183156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH);
184156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    if (oldVal == maxDayOfMonth && newVal == 1) {
185156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.DAY_OF_MONTH, 1);
186156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    } else if (oldVal == 1 && newVal == maxDayOfMonth) {
187156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.DAY_OF_MONTH, -1);
188156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    } else {
189156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.DAY_OF_MONTH, newVal - oldVal);
190156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    }
191156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                } else if (picker == mMonthSpinner) {
192156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    if (oldVal == 11 && newVal == 0) {
193156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.MONTH, 1);
194156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    } else if (oldVal == 0 && newVal == 11) {
195156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.MONTH, -1);
196156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    } else {
197156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.add(Calendar.MONTH, newVal - oldVal);
198156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    }
199156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                } else if (picker == mYearSpinner) {
200156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    mTempDate.set(Calendar.YEAR, newVal);
201156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                } else {
202156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                    throw new IllegalArgumentException();
203156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                }
204156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                // now set the date to the adjusted one
205156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                setDate(mTempDate.get(Calendar.YEAR), mTempDate.get(Calendar.MONTH),
206156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                        mTempDate.get(Calendar.DAY_OF_MONTH));
20758f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov                updateSpinners();
20858f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov                updateCalendarView();
209156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                notifyDateChanged();
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        };
2125fe1e6221ea3bab3120f5b9c0ceacaf59d116c05Eric Fischer
213e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mSpinners = (LinearLayout) findViewById(R.id.pickers);
214e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
215e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        // calendar view day-picker
216e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView = (CalendarView) findViewById(R.id.calendar_view);
217e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView.setOnDateChangeListener(new CalendarView.OnDateChangeListener() {
218e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            public void onSelectedDayChange(CalendarView view, int year, int month, int monthDay) {
219156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                setDate(year, month, monthDay);
22058f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov                updateSpinners();
221156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                notifyDateChanged();
22228104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov            }
22328104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov        });
22428104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov
22550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        // day
226e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mDaySpinner = (NumberPicker) findViewById(R.id.day);
227d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio        mDaySpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
228e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mDaySpinner.setOnLongPressUpdateInterval(100);
229e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mDaySpinner.setOnValueChangedListener(onChangeListener);
2306304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        mDaySpinnerInput = (EditText) mDaySpinner.findViewById(R.id.numberpicker_input);
2315fe1e6221ea3bab3120f5b9c0ceacaf59d116c05Eric Fischer
23250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        // month
233e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner = (NumberPicker) findViewById(R.id.month);
234e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setMinValue(0);
235e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setMaxValue(mNumberOfMonths - 1);
236f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mMonthSpinner.setDisplayedValues(mShortMonths);
237e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setOnLongPressUpdateInterval(200);
238e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setOnValueChangedListener(onChangeListener);
2396304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        mMonthSpinnerInput = (EditText) mMonthSpinner.findViewById(R.id.numberpicker_input);
24050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
24150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        // year
242e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mYearSpinner = (NumberPicker) findViewById(R.id.year);
243e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mYearSpinner.setOnLongPressUpdateInterval(100);
244e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mYearSpinner.setOnValueChangedListener(onChangeListener);
2456304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        mYearSpinnerInput = (EditText) mYearSpinner.findViewById(R.id.numberpicker_input);
246e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
247e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        // show only what the user required but make sure we
248e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        // show something and the spinners have higher priority
249e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        if (!spinnersShown && !calendarViewShown) {
250e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            setSpinnersShown(true);
251e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        } else {
252e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            setSpinnersShown(spinnersShown);
253e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            setCalendarViewShown(calendarViewShown);
25413427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        }
255e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
25613427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        // set the min date giving priority of the minDate over startYear
25713427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        mTempDate.clear();
25813427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        if (!TextUtils.isEmpty(minDate)) {
25913427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov            if (!parseDate(minDate, mTempDate)) {
260e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                mTempDate.set(startYear, 0, 1);
261e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            }
26213427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        } else {
26313427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov            mTempDate.set(startYear, 0, 1);
26413427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        }
26513427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        setMinDate(mTempDate.getTimeInMillis());
26613427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov
26713427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        // set the max date giving priority of the maxDate over endYear
26813427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        mTempDate.clear();
26913427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        if (!TextUtils.isEmpty(maxDate)) {
27013427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov            if (!parseDate(maxDate, mTempDate)) {
271e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                mTempDate.set(endYear, 11, 31);
272e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            }
27313427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        } else {
27413427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov            mTempDate.set(endYear, 11, 31);
275e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        }
27613427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        setMaxDate(mTempDate.getTimeInMillis());
27713427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov
27813427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        // initialize to current date
27913427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        mCurrentDate.setTimeInMillis(System.currentTimeMillis());
28013427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov        init(mCurrentDate.get(Calendar.YEAR), mCurrentDate.get(Calendar.MONTH), mCurrentDate
28113427a04de835677f9e5f727298f168b88faa562Svetoslav Ganov                .get(Calendar.DAY_OF_MONTH), null);
282e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
283e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        // re-order the number spinners to match the current date format
284e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        reorderSpinners();
2853fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov
2864213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov        // accessibility
287d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        setContentDescriptions();
2884213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov
2894213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov        // If not explicitly specified this view is important for accessibility.
2904213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov        if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
2914213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
2924213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov        }
293e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
294e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
295e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
296e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Gets the minimal date supported by this {@link DatePicker} in
297e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * milliseconds since January 1, 1970 00:00:00 in
298e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * {@link TimeZone#getDefault()} time zone.
299e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * <p>
300e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Note: The default minimal date is 01/01/1900.
301e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * <p>
302e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
303e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @return The minimal supported date.
304e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
305e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public long getMinDate() {
306e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        return mCalendarView.getMinDate();
307e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
308e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
309e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
310e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Sets the minimal date supported by this {@link NumberPicker} in
311e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * milliseconds since January 1, 1970 00:00:00 in
312e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * {@link TimeZone#getDefault()} time zone.
313e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
314e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @param minDate The minimal supported date.
315e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
316e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public void setMinDate(long minDate) {
317e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mTempDate.setTimeInMillis(minDate);
318e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR)
319e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMinDate.get(Calendar.DAY_OF_YEAR)) {
320e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            return;
321e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        }
322e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMinDate.setTimeInMillis(minDate);
323e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView.setMinDate(minDate);
324156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        if (mCurrentDate.before(mMinDate)) {
325156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
326156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            updateCalendarView();
327156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        }
328156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        updateSpinners();
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
33128104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov    /**
332e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Gets the maximal date supported by this {@link DatePicker} in
333e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * milliseconds since January 1, 1970 00:00:00 in
334e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * {@link TimeZone#getDefault()} time zone.
335e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * <p>
336e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Note: The default maximal date is 12/31/2100.
33728104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov     * <p>
33828104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov     *
339e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @return The maximal supported date.
340e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
341e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public long getMaxDate() {
342e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        return mCalendarView.getMaxDate();
343e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
344e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
345e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
346e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Sets the maximal date supported by this {@link DatePicker} in
347e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * milliseconds since January 1, 1970 00:00:00 in
348e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * {@link TimeZone#getDefault()} time zone.
349e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
350e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @param maxDate The maximal supported date.
35128104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov     */
352e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public void setMaxDate(long maxDate) {
353e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mTempDate.setTimeInMillis(maxDate);
354e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)
355e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate.get(Calendar.DAY_OF_YEAR)) {
356e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            return;
35728104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov        }
358e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMaxDate.setTimeInMillis(maxDate);
359e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView.setMaxDate(maxDate);
360156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        if (mCurrentDate.after(mMaxDate)) {
361156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
362156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            updateCalendarView();
363156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        }
364156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        updateSpinners();
36528104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov    }
36628104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setEnabled(boolean enabled) {
36951c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        if (mIsEnabled == enabled) {
37051c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov            return;
37151c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        }
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.setEnabled(enabled);
373e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mDaySpinner.setEnabled(enabled);
374e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMonthSpinner.setEnabled(enabled);
375e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mYearSpinner.setEnabled(enabled);
376e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView.setEnabled(enabled);
37751c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        mIsEnabled = enabled;
37851c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov    }
37951c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov
38051c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov    @Override
38151c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov    public boolean isEnabled() {
38251c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        return mIsEnabled;
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3858a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov    @Override
3863fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
3873fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        onPopulateAccessibilityEvent(event);
3883fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        return true;
3893fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov    }
3903fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov
3913fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov    @Override
392736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
393736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov        super.onPopulateAccessibilityEvent(event);
394736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov
3953fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
3968a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        String selectedDateUtterance = DateUtils.formatDateTime(mContext,
3978a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov                mCurrentDate.getTimeInMillis(), flags);
3988a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        event.getText().add(selectedDateUtterance);
3998a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov    }
4008a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov
401f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    @Override
4028a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
4038a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityEvent(event);
4048a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        event.setClassName(DatePicker.class.getName());
4058a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
4068a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
4078a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
4088a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
4098a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityNodeInfo(info);
4108a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        info.setClassName(DatePicker.class.getName());
4118a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
4128a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
4138a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
414f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    protected void onConfigurationChanged(Configuration newConfig) {
415f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        super.onConfigurationChanged(newConfig);
416f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        setCurrentLocale(newConfig.locale);
417f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    }
418f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
41950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
420e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Gets whether the {@link CalendarView} is shown.
421e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
422e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @return True if the calendar view is shown.
4235f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov     * @see #getCalendarView()
424e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
425e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public boolean getCalendarViewShown() {
426e10837f444c3da40a50a269e696afac63729bce3Svetoslav        return (mCalendarView.getVisibility() == View.VISIBLE);
427e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
428e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
429e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
4305f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov     * Gets the {@link CalendarView}.
4315f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov     *
4325f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov     * @return The calendar view.
4335f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov     * @see #getCalendarViewShown()
4345f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov     */
4355f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov    public CalendarView getCalendarView () {
4365f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov        return mCalendarView;
4375f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov    }
4385f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov
4395f3f6ce154ca1a0075f8ca13872d74f935acbe3dSvetoslav Ganov    /**
440e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Sets whether the {@link CalendarView} is shown.
441e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
442e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @param shown True if the calendar view is to be shown.
443e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
444e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public void setCalendarViewShown(boolean shown) {
445e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mCalendarView.setVisibility(shown ? VISIBLE : GONE);
446e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
447e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
448e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
449e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Gets whether the spinners are shown.
450e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
451e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @return True if the spinners are shown.
45250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
453e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public boolean getSpinnersShown() {
454e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        return mSpinners.isShown();
455e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
456e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
457e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
458e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Sets whether the spinners are shown.
459e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     *
460e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @param shown True if the spinners are to be shown.
461e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
462e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    public void setSpinnersShown(boolean shown) {
463e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mSpinners.setVisibility(shown ? VISIBLE : GONE);
464e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
465e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
466e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    /**
467f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     * Sets the current locale.
468f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     *
469f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     * @param locale The current locale.
470f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     */
471f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private void setCurrentLocale(Locale locale) {
472f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        if (locale.equals(mCurrentLocale)) {
473f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov            return;
474f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        }
475f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
476f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mCurrentLocale = locale;
477f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
478f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mTempDate = getCalendarForLocale(mTempDate, locale);
479f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mMinDate = getCalendarForLocale(mMinDate, locale);
480f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mMaxDate = getCalendarForLocale(mMaxDate, locale);
481f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mCurrentDate = getCalendarForLocale(mCurrentDate, locale);
482f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
483f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1;
484949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes        mShortMonths = new DateFormatSymbols().getShortMonths();
485949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes
486949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes        if (usingNumericMonths()) {
487949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes            // We're in a locale where a date should either be all-numeric, or all-text.
488949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes            // All-text would require custom NumberPicker formatters for day and year.
489949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes            mShortMonths = new String[mNumberOfMonths];
490949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes            for (int i = 0; i < mNumberOfMonths; ++i) {
491949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes                mShortMonths[i] = String.format("%d", i + 1);
492949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes            }
493f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        }
494f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    }
495f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
496f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    /**
497949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes     * Tests whether the current locale is one where there are no real month names,
498949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes     * such as Chinese, Japanese, or Korean locales.
499949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes     */
500949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes    private boolean usingNumericMonths() {
501949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes        return Character.isDigit(mShortMonths[Calendar.JANUARY].charAt(0));
502949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes    }
503949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes
504949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes    /**
505f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     * Gets a calendar for locale bootstrapped with the value of a given calendar.
506f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     *
507f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     * @param oldCalendar The old calendar.
508f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     * @param locale The locale.
509f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     */
510f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
511f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        if (oldCalendar == null) {
512f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov            return Calendar.getInstance(locale);
513f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        } else {
514f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov            final long currentTimeMillis = oldCalendar.getTimeInMillis();
515f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov            Calendar newCalendar = Calendar.getInstance(locale);
516f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov            newCalendar.setTimeInMillis(currentTimeMillis);
517f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov            return newCalendar;
518f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        }
519f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    }
520f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
521f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    /**
522f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov     * Reorders the spinners according to the date format that is
523f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov     * explicitly set by the user and if no such is set fall back
524f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov     * to the current locale's default format.
525e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     */
526e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private void reorderSpinners() {
527f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov        mSpinners.removeAllViews();
528659f145278ffd85f934a435dbec47ead685caf59Elliott Hughes        // We use numeric spinners for year and day, but textual months. Ask icu4c what
529659f145278ffd85f934a435dbec47ead685caf59Elliott Hughes        // order the user's locale uses for that combination. http://b/7207103.
530659f145278ffd85f934a435dbec47ead685caf59Elliott Hughes        String pattern = ICU.getBestDateTimePattern("yyyyMMMdd", Locale.getDefault().toString());
531659f145278ffd85f934a435dbec47ead685caf59Elliott Hughes        char[] order = ICU.getDateFormatOrder(pattern);
532a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov        final int spinnerCount = order.length;
533a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov        for (int i = 0; i < spinnerCount; i++) {
534f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov            switch (order[i]) {
535659f145278ffd85f934a435dbec47ead685caf59Elliott Hughes                case 'd':
536f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                    mSpinners.addView(mDaySpinner);
537a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov                    setImeOptions(mDaySpinner, spinnerCount, i);
538f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                    break;
539659f145278ffd85f934a435dbec47ead685caf59Elliott Hughes                case 'M':
540f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                    mSpinners.addView(mMonthSpinner);
541a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov                    setImeOptions(mMonthSpinner, spinnerCount, i);
542f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                    break;
543659f145278ffd85f934a435dbec47ead685caf59Elliott Hughes                case 'y':
544f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                    mSpinners.addView(mYearSpinner);
545a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov                    setImeOptions(mYearSpinner, spinnerCount, i);
546f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                    break;
547f583dd37643f495642cd64e9b8e6a0a9e0836ff1Svetoslav Ganov                default:
548659f145278ffd85f934a435dbec47ead685caf59Elliott Hughes                    throw new IllegalArgumentException(Arrays.toString(order));
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
55350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
55450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * Updates the current date.
55550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     *
55650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @param year The year.
55750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @param month The month which is <strong>starting from zero</strong>.
55850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @param dayOfMonth The day of the month.
55950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
56050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    public void updateDate(int year, int month, int dayOfMonth) {
561156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        if (!isNewDate(year, month, dayOfMonth)) {
562156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            return;
563dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root        }
564156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        setDate(year, month, dayOfMonth);
56558f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateSpinners();
56658f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateCalendarView();
567156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        notifyDateChanged();
568dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root    }
569dddda8d188408ff18935b1b0e15a00fe012a03daKenny Root
57050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    // Override so we are in complete control of save / restore for this widget.
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        dispatchThawSelfOnly(container);
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected Parcelable onSaveInstanceState() {
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Parcelable superState = super.onSaveInstanceState();
579156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        return new SavedState(superState, getYear(), getMonth(), getDayOfMonth());
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onRestoreInstanceState(Parcelable state) {
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SavedState ss = (SavedState) state;
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onRestoreInstanceState(ss.getSuperState());
586156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        setDate(ss.mYear, ss.mMonth, ss.mDay);
58758f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateSpinners();
58858f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateCalendarView();
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
59250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * Initialize the state. If the provided values designate an inconsistent
593e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * date the values are normalized before updating the spinners.
59450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     *
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param year The initial year.
59650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @param monthOfYear The initial month <strong>starting from zero</strong>.
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param dayOfMonth The initial day of the month.
59850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @param onDateChangedListener How user is notified date is changed by
59950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     *            user, can be null.
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void init(int year, int monthOfYear, int dayOfMonth,
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            OnDateChangedListener onDateChangedListener) {
603156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        setDate(year, monthOfYear, dayOfMonth);
60458f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateSpinners();
60558f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov        updateCalendarView();
6062f136a874d240cc7e85e8de9c7644a7daa9532daSvetoslav Ganov        mOnDateChangedListener = onDateChangedListener;
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
60950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
610e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * Parses the given <code>date</code> and in case of success sets the result
611e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * to the <code>outDate</code>.
612a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov     *
613e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov     * @return True if the date was parsed.
614a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov     */
615e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private boolean parseDate(String date, Calendar outDate) {
616e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        try {
617e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            outDate.setTime(mDateFormat.parse(date));
618e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            return true;
619e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        } catch (ParseException e) {
620e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT);
621e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            return false;
622e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        }
623a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov    }
624a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov
625156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov    private boolean isNewDate(int year, int month, int dayOfMonth) {
626156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        return (mCurrentDate.get(Calendar.YEAR) != year
627156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                || mCurrentDate.get(Calendar.MONTH) != dayOfMonth
628156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                || mCurrentDate.get(Calendar.DAY_OF_MONTH) != month);
629156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov    }
630e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
631156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov    private void setDate(int year, int month, int dayOfMonth) {
632156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mCurrentDate.set(year, month, dayOfMonth);
633e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        if (mCurrentDate.before(mMinDate)) {
634e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
635e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        } else if (mCurrentDate.after(mMaxDate)) {
636e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
637e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        }
638e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    }
639e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
640156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov    private void updateSpinners() {
641156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        // set the spinner ranges respecting the min and max dates
642156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        if (mCurrentDate.equals(mMinDate)) {
643156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMinValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
644156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
645156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setWrapSelectorWheel(false);
646156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setDisplayedValues(null);
647156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMinValue(mCurrentDate.get(Calendar.MONTH));
648156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.MONTH));
649156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setWrapSelectorWheel(false);
650156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        } else if (mCurrentDate.equals(mMaxDate)) {
651156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.DAY_OF_MONTH));
652156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMaxValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
653156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setWrapSelectorWheel(false);
654156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setDisplayedValues(null);
655156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.MONTH));
656156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMaxValue(mCurrentDate.get(Calendar.MONTH));
657156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setWrapSelectorWheel(false);
658156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        } else {
659156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMinValue(1);
660156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
661156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mDaySpinner.setWrapSelectorWheel(true);
662156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setDisplayedValues(null);
663156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMinValue(0);
664156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setMaxValue(11);
665156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mMonthSpinner.setWrapSelectorWheel(true);
666e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        }
667e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov
668156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        // make sure the month names are a zero based array
669156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        // with the months in the month spinner
670f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        String[] displayedValues = Arrays.copyOfRange(mShortMonths,
671156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov                mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1);
672156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mMonthSpinner.setDisplayedValues(displayedValues);
673156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov
674156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        // year spinner range does not change based on the current date
675156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR));
676156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR));
677156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mYearSpinner.setWrapSelectorWheel(false);
678156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov
679156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        // set the spinner values
680156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR));
681156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH));
682156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
683e9a74a1a31f82391d44840aa17293021fcab6837Hyejin Kim
684949e9df25bccb736675f950591d3a286ae4052fcElliott Hughes        if (usingNumericMonths()) {
685e9a74a1a31f82391d44840aa17293021fcab6837Hyejin Kim            mMonthSpinnerInput.setRawInputType(InputType.TYPE_CLASS_NUMBER);
686e9a74a1a31f82391d44840aa17293021fcab6837Hyejin Kim        }
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
68950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
690156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov     * Updates the calendar view with the current date.
69150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
692e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private void updateCalendarView() {
693156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov         mCalendarView.setDate(mCurrentDate.getTimeInMillis(), false, false);
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
69650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
69750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @return The selected year.
69850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getYear() {
700156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        return mCurrentDate.get(Calendar.YEAR);
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
70350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
70450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @return The selected month.
70550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getMonth() {
707156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        return mCurrentDate.get(Calendar.MONTH);
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
71050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
71150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * @return The selected day of month.
71250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getDayOfMonth() {
714156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov        return mCurrentDate.get(Calendar.DAY_OF_MONTH);
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7162bf761c20253222a763bce9a63d14c48ab08a556Suchi Amalapurapu
71750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
71850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * Notifies the listener, if such, for a change in the selected date.
71950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
72050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    private void notifyDateChanged() {
7218a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
72250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        if (mOnDateChangedListener != null) {
723156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov            mOnDateChangedListener.onDateChanged(this, getYear(), getMonth(), getDayOfMonth());
7242bf761c20253222a763bce9a63d14c48ab08a556Suchi Amalapurapu        }
7252bf761c20253222a763bce9a63d14c48ab08a556Suchi Amalapurapu    }
726e3491b6b5f1d3fb871074766597b275d9f682faaKenneth Andersson
72750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    /**
728a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov     * Sets the IME options for a spinner based on its ordering.
729a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov     *
730a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov     * @param spinner The spinner.
731a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov     * @param spinnerCount The total spinner count.
732a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov     * @param spinnerIndex The index of the given spinner.
733a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov     */
734a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov    private void setImeOptions(NumberPicker spinner, int spinnerCount, int spinnerIndex) {
735a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov        final int imeOptions;
736a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov        if (spinnerIndex < spinnerCount - 1) {
737a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov            imeOptions = EditorInfo.IME_ACTION_NEXT;
738a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov        } else {
739a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov            imeOptions = EditorInfo.IME_ACTION_DONE;
740a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov        }
741a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov        TextView input = (TextView) spinner.findViewById(R.id.numberpicker_input);
742a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov        input.setImeOptions(imeOptions);
743a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov    }
744a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov
745a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov    private void setContentDescriptions() {
746a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov        // Day
747d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        trySetContentDescription(mDaySpinner, R.id.increment,
748d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov                R.string.date_picker_increment_day_button);
749d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        trySetContentDescription(mDaySpinner, R.id.decrement,
750d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov                R.string.date_picker_decrement_day_button);
751a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov        // Month
752d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        trySetContentDescription(mMonthSpinner, R.id.increment,
753d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov                R.string.date_picker_increment_month_button);
754d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        trySetContentDescription(mMonthSpinner, R.id.decrement,
755d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov                R.string.date_picker_decrement_month_button);
756a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov        // Year
757d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        trySetContentDescription(mYearSpinner, R.id.increment,
758d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov                R.string.date_picker_increment_year_button);
759d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        trySetContentDescription(mYearSpinner, R.id.decrement,
760d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov                R.string.date_picker_decrement_year_button);
761d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov    }
762d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov
763d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov    private void trySetContentDescription(View root, int viewId, int contDescResId) {
764d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        View target = root.findViewById(viewId);
765d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        if (target != null) {
766d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov            target.setContentDescription(mContext.getString(contDescResId));
767d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        }
768a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov    }
769a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov
7706304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov    private void updateInputState() {
7716304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        // Make sure that if the user changes the value and the IME is active
7726304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        // for one of the inputs if this widget, the IME is closed. If the user
7736304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        // changed the value via the IME and there is a next input the IME will
7746304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        // be shown, otherwise the user chose another means of changing the
7756304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        // value and having the IME up makes no sense.
7766304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
7776304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        if (inputMethodManager != null) {
7786304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov            if (inputMethodManager.isActive(mYearSpinnerInput)) {
7796304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                mYearSpinnerInput.clearFocus();
7806304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
7816304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov            } else if (inputMethodManager.isActive(mMonthSpinnerInput)) {
7826304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                mMonthSpinnerInput.clearFocus();
7836304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
7846304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov            } else if (inputMethodManager.isActive(mDaySpinnerInput)) {
7856304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                mDaySpinnerInput.clearFocus();
7866304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
7876304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov            }
7886304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        }
7896304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov    }
7906304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov
791a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov    /**
79250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     * Class for managing state storing/restoring.
79350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov     */
79450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov    private static class SavedState extends BaseSavedState {
79550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
79650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        private final int mYear;
79750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
79850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        private final int mMonth;
79950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
80050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        private final int mDay;
80150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
80250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        /**
80350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         * Constructor called from {@link DatePicker#onSaveInstanceState()}
80450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         */
80550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        private SavedState(Parcelable superState, int year, int month, int day) {
80650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            super(superState);
80750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mYear = year;
80850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mMonth = month;
80950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mDay = day;
81050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        }
81150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
81250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        /**
81350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         * Constructor called from {@link #CREATOR}
81450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov         */
81550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        private SavedState(Parcel in) {
81650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            super(in);
81750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mYear = in.readInt();
81850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mMonth = in.readInt();
81950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            mDay = in.readInt();
820e3491b6b5f1d3fb871074766597b275d9f682faaKenneth Andersson        }
82150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
82250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        @Override
82350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        public void writeToParcel(Parcel dest, int flags) {
82450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            super.writeToParcel(dest, flags);
82550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            dest.writeInt(mYear);
82650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            dest.writeInt(mMonth);
82750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            dest.writeInt(mDay);
82850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        }
82950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
83050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        @SuppressWarnings("all")
83150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        // suppress unused and hiding
83250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
83350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
83450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            public SavedState createFromParcel(Parcel in) {
83550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov                return new SavedState(in);
83650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            }
83750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
83850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            public SavedState[] newArray(int size) {
83950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov                return new SavedState[size];
84050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov            }
84150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov        };
842e3491b6b5f1d3fb871074766597b275d9f682faaKenneth Andersson    }
8433fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov}
844