Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.widget;
     18 
     19 import android.annotation.IntDef;
     20 import android.annotation.Nullable;
     21 import android.annotation.TestApi;
     22 import android.annotation.Widget;
     23 import android.content.Context;
     24 import android.content.res.Configuration;
     25 import android.content.res.TypedArray;
     26 import android.icu.util.Calendar;
     27 import android.icu.util.TimeZone;
     28 import android.os.Parcel;
     29 import android.os.Parcelable;
     30 import android.text.format.DateUtils;
     31 import android.util.AttributeSet;
     32 import android.util.Log;
     33 import android.util.SparseArray;
     34 import android.view.View;
     35 import android.view.ViewStructure;
     36 import android.view.accessibility.AccessibilityEvent;
     37 import android.view.autofill.AutofillManager;
     38 import android.view.autofill.AutofillValue;
     39 
     40 import com.android.internal.R;
     41 
     42 import java.lang.annotation.Retention;
     43 import java.lang.annotation.RetentionPolicy;
     44 import java.util.Locale;
     45 
     46 /**
     47  * Provides a widget for selecting a date.
     48  * <p>
     49  * When the {@link android.R.styleable#DatePicker_datePickerMode} attribute is
     50  * set to {@code spinner}, the date can be selected using year, month, and day
     51  * spinners or a {@link CalendarView}. The set of spinners and the calendar
     52  * view are automatically synchronized. The client can customize whether only
     53  * the spinners, or only the calendar view, or both to be displayed.
     54  * </p>
     55  * <p>
     56  * When the {@link android.R.styleable#DatePicker_datePickerMode} attribute is
     57  * set to {@code calendar}, the month and day can be selected using a
     58  * calendar-style view while the year can be selected separately using a list.
     59  * </p>
     60  * <p>
     61  * See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
     62  * guide.
     63  * </p>
     64  * <p>
     65  * For a dialog using this view, see {@link android.app.DatePickerDialog}.
     66  * </p>
     67  *
     68  * @attr ref android.R.styleable#DatePicker_startYear
     69  * @attr ref android.R.styleable#DatePicker_endYear
     70  * @attr ref android.R.styleable#DatePicker_maxDate
     71  * @attr ref android.R.styleable#DatePicker_minDate
     72  * @attr ref android.R.styleable#DatePicker_spinnersShown
     73  * @attr ref android.R.styleable#DatePicker_calendarViewShown
     74  * @attr ref android.R.styleable#DatePicker_dayOfWeekBackground
     75  * @attr ref android.R.styleable#DatePicker_dayOfWeekTextAppearance
     76  * @attr ref android.R.styleable#DatePicker_headerBackground
     77  * @attr ref android.R.styleable#DatePicker_headerMonthTextAppearance
     78  * @attr ref android.R.styleable#DatePicker_headerDayOfMonthTextAppearance
     79  * @attr ref android.R.styleable#DatePicker_headerYearTextAppearance
     80  * @attr ref android.R.styleable#DatePicker_yearListItemTextAppearance
     81  * @attr ref android.R.styleable#DatePicker_yearListSelectorColor
     82  * @attr ref android.R.styleable#DatePicker_calendarTextColor
     83  * @attr ref android.R.styleable#DatePicker_datePickerMode
     84  */
     85 @Widget
     86 public class DatePicker extends FrameLayout {
     87     private static final String LOG_TAG = DatePicker.class.getSimpleName();
     88 
     89     /**
     90      * Presentation mode for the Holo-style date picker that uses a set of
     91      * {@link android.widget.NumberPicker}s.
     92      *
     93      * @see #getMode()
     94      * @hide Visible for testing only.
     95      */
     96     @TestApi
     97     public static final int MODE_SPINNER = 1;
     98 
     99     /**
    100      * Presentation mode for the Material-style date picker that uses a
    101      * calendar.
    102      *
    103      * @see #getMode()
    104      * @hide Visible for testing only.
    105      */
    106     @TestApi
    107     public static final int MODE_CALENDAR = 2;
    108 
    109     /** @hide */
    110     @IntDef({MODE_SPINNER, MODE_CALENDAR})
    111     @Retention(RetentionPolicy.SOURCE)
    112     public @interface DatePickerMode {}
    113 
    114     private final DatePickerDelegate mDelegate;
    115 
    116     @DatePickerMode
    117     private final int mMode;
    118 
    119     /**
    120      * The callback used to indicate the user changed the date.
    121      */
    122     public interface OnDateChangedListener {
    123 
    124         /**
    125          * Called upon a date change.
    126          *
    127          * @param view The view associated with this listener.
    128          * @param year The year that was set.
    129          * @param monthOfYear The month that was set (0-11) for compatibility
    130          *            with {@link java.util.Calendar}.
    131          * @param dayOfMonth The day of the month that was set.
    132          */
    133         void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth);
    134     }
    135 
    136     public DatePicker(Context context) {
    137         this(context, null);
    138     }
    139 
    140     public DatePicker(Context context, AttributeSet attrs) {
    141         this(context, attrs, R.attr.datePickerStyle);
    142     }
    143 
    144     public DatePicker(Context context, AttributeSet attrs, int defStyleAttr) {
    145         this(context, attrs, defStyleAttr, 0);
    146     }
    147 
    148     public DatePicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    149         super(context, attrs, defStyleAttr, defStyleRes);
    150 
    151         // DatePicker is important by default, unless app developer overrode attribute.
    152         if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) {
    153             setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES);
    154         }
    155 
    156         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
    157                 defStyleAttr, defStyleRes);
    158         final boolean isDialogMode = a.getBoolean(R.styleable.DatePicker_dialogMode, false);
    159         final int requestedMode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER);
    160         final int firstDayOfWeek = a.getInt(R.styleable.DatePicker_firstDayOfWeek, 0);
    161         a.recycle();
    162 
    163         if (requestedMode == MODE_CALENDAR && isDialogMode) {
    164             // You want MODE_CALENDAR? YOU CAN'T HANDLE MODE_CALENDAR! Well,
    165             // maybe you can depending on your screen size. Let's check...
    166             mMode = context.getResources().getInteger(R.integer.date_picker_mode);
    167         } else {
    168             mMode = requestedMode;
    169         }
    170 
    171         switch (mMode) {
    172             case MODE_CALENDAR:
    173                 mDelegate = createCalendarUIDelegate(context, attrs, defStyleAttr, defStyleRes);
    174                 break;
    175             case MODE_SPINNER:
    176             default:
    177                 mDelegate = createSpinnerUIDelegate(context, attrs, defStyleAttr, defStyleRes);
    178                 break;
    179         }
    180 
    181         if (firstDayOfWeek != 0) {
    182             setFirstDayOfWeek(firstDayOfWeek);
    183         }
    184 
    185         mDelegate.setAutoFillChangeListener((v, y, m, d) -> {
    186             final AutofillManager afm = context.getSystemService(AutofillManager.class);
    187             if (afm != null) {
    188                 afm.notifyValueChanged(this);
    189             }
    190         });
    191     }
    192 
    193     private DatePickerDelegate createSpinnerUIDelegate(Context context, AttributeSet attrs,
    194             int defStyleAttr, int defStyleRes) {
    195         return new DatePickerSpinnerDelegate(this, context, attrs, defStyleAttr, defStyleRes);
    196     }
    197 
    198     private DatePickerDelegate createCalendarUIDelegate(Context context, AttributeSet attrs,
    199             int defStyleAttr, int defStyleRes) {
    200         return new DatePickerCalendarDelegate(this, context, attrs, defStyleAttr,
    201                 defStyleRes);
    202     }
    203 
    204     /**
    205      * @return the picker's presentation mode, one of {@link #MODE_CALENDAR} or
    206      *         {@link #MODE_SPINNER}
    207      * @attr ref android.R.styleable#DatePicker_datePickerMode
    208      * @hide Visible for testing only.
    209      */
    210     @DatePickerMode
    211     @TestApi
    212     public int getMode() {
    213         return mMode;
    214     }
    215 
    216     /**
    217      * Initialize the state. If the provided values designate an inconsistent
    218      * date the values are normalized before updating the spinners.
    219      *
    220      * @param year The initial year.
    221      * @param monthOfYear The initial month <strong>starting from zero</strong>.
    222      * @param dayOfMonth The initial day of the month.
    223      * @param onDateChangedListener How user is notified date is changed by
    224      *            user, can be null.
    225      */
    226     public void init(int year, int monthOfYear, int dayOfMonth,
    227                      OnDateChangedListener onDateChangedListener) {
    228         mDelegate.init(year, monthOfYear, dayOfMonth, onDateChangedListener);
    229     }
    230 
    231     /**
    232      * Set the callback that indicates the date has been adjusted by the user.
    233      *
    234      * @param onDateChangedListener How user is notified date is changed by
    235      *            user, can be null.
    236      */
    237     public void setOnDateChangedListener(OnDateChangedListener onDateChangedListener) {
    238         mDelegate.setOnDateChangedListener(onDateChangedListener);
    239     }
    240 
    241     /**
    242      * Update the current date.
    243      *
    244      * @param year The year.
    245      * @param month The month which is <strong>starting from zero</strong>.
    246      * @param dayOfMonth The day of the month.
    247      */
    248     public void updateDate(int year, int month, int dayOfMonth) {
    249         mDelegate.updateDate(year, month, dayOfMonth);
    250     }
    251 
    252     /**
    253      * @return The selected year.
    254      */
    255     public int getYear() {
    256         return mDelegate.getYear();
    257     }
    258 
    259     /**
    260      * @return The selected month.
    261      */
    262     public int getMonth() {
    263         return mDelegate.getMonth();
    264     }
    265 
    266     /**
    267      * @return The selected day of month.
    268      */
    269     public int getDayOfMonth() {
    270         return mDelegate.getDayOfMonth();
    271     }
    272 
    273     /**
    274      * Gets the minimal date supported by this {@link DatePicker} in
    275      * milliseconds since January 1, 1970 00:00:00 in
    276      * {@link TimeZone#getDefault()} time zone.
    277      * <p>
    278      * Note: The default minimal date is 01/01/1900.
    279      * <p>
    280      *
    281      * @return The minimal supported date.
    282      */
    283     public long getMinDate() {
    284         return mDelegate.getMinDate().getTimeInMillis();
    285     }
    286 
    287     /**
    288      * Sets the minimal date supported by this {@link NumberPicker} in
    289      * milliseconds since January 1, 1970 00:00:00 in
    290      * {@link TimeZone#getDefault()} time zone.
    291      *
    292      * @param minDate The minimal supported date.
    293      */
    294     public void setMinDate(long minDate) {
    295         mDelegate.setMinDate(minDate);
    296     }
    297 
    298     /**
    299      * Gets the maximal date supported by this {@link DatePicker} in
    300      * milliseconds since January 1, 1970 00:00:00 in
    301      * {@link TimeZone#getDefault()} time zone.
    302      * <p>
    303      * Note: The default maximal date is 12/31/2100.
    304      * <p>
    305      *
    306      * @return The maximal supported date.
    307      */
    308     public long getMaxDate() {
    309         return mDelegate.getMaxDate().getTimeInMillis();
    310     }
    311 
    312     /**
    313      * Sets the maximal date supported by this {@link DatePicker} in
    314      * milliseconds since January 1, 1970 00:00:00 in
    315      * {@link TimeZone#getDefault()} time zone.
    316      *
    317      * @param maxDate The maximal supported date.
    318      */
    319     public void setMaxDate(long maxDate) {
    320         mDelegate.setMaxDate(maxDate);
    321     }
    322 
    323     /**
    324      * Sets the callback that indicates the current date is valid.
    325      *
    326      * @param callback the callback, may be null
    327      * @hide
    328      */
    329     public void setValidationCallback(@Nullable ValidationCallback callback) {
    330         mDelegate.setValidationCallback(callback);
    331     }
    332 
    333     @Override
    334     public void setEnabled(boolean enabled) {
    335         if (mDelegate.isEnabled() == enabled) {
    336             return;
    337         }
    338         super.setEnabled(enabled);
    339         mDelegate.setEnabled(enabled);
    340     }
    341 
    342     @Override
    343     public boolean isEnabled() {
    344         return mDelegate.isEnabled();
    345     }
    346 
    347     /** @hide */
    348     @Override
    349     public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
    350         return mDelegate.dispatchPopulateAccessibilityEvent(event);
    351     }
    352 
    353     /** @hide */
    354     @Override
    355     public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
    356         super.onPopulateAccessibilityEventInternal(event);
    357         mDelegate.onPopulateAccessibilityEvent(event);
    358     }
    359 
    360     @Override
    361     public CharSequence getAccessibilityClassName() {
    362         return DatePicker.class.getName();
    363     }
    364 
    365     @Override
    366     protected void onConfigurationChanged(Configuration newConfig) {
    367         super.onConfigurationChanged(newConfig);
    368         mDelegate.onConfigurationChanged(newConfig);
    369     }
    370 
    371     /**
    372      * Sets the first day of week.
    373      *
    374      * @param firstDayOfWeek The first day of the week conforming to the
    375      *            {@link CalendarView} APIs.
    376      * @see Calendar#SUNDAY
    377      * @see Calendar#MONDAY
    378      * @see Calendar#TUESDAY
    379      * @see Calendar#WEDNESDAY
    380      * @see Calendar#THURSDAY
    381      * @see Calendar#FRIDAY
    382      * @see Calendar#SATURDAY
    383      *
    384      * @attr ref android.R.styleable#DatePicker_firstDayOfWeek
    385      */
    386     public void setFirstDayOfWeek(int firstDayOfWeek) {
    387         if (firstDayOfWeek < Calendar.SUNDAY || firstDayOfWeek > Calendar.SATURDAY) {
    388             throw new IllegalArgumentException("firstDayOfWeek must be between 1 and 7");
    389         }
    390         mDelegate.setFirstDayOfWeek(firstDayOfWeek);
    391     }
    392 
    393     /**
    394      * Gets the first day of week.
    395      *
    396      * @return The first day of the week conforming to the {@link CalendarView}
    397      *         APIs.
    398      * @see Calendar#SUNDAY
    399      * @see Calendar#MONDAY
    400      * @see Calendar#TUESDAY
    401      * @see Calendar#WEDNESDAY
    402      * @see Calendar#THURSDAY
    403      * @see Calendar#FRIDAY
    404      * @see Calendar#SATURDAY
    405      *
    406      * @attr ref android.R.styleable#DatePicker_firstDayOfWeek
    407      */
    408     public int getFirstDayOfWeek() {
    409         return mDelegate.getFirstDayOfWeek();
    410     }
    411 
    412     /**
    413      * Returns whether the {@link CalendarView} is shown.
    414      * <p>
    415      * <strong>Note:</strong> This method returns {@code false} when the
    416      * {@link android.R.styleable#DatePicker_datePickerMode} attribute is set
    417      * to {@code calendar}.
    418      *
    419      * @return {@code true} if the calendar view is shown
    420      * @see #getCalendarView()
    421      * @deprecated Not supported by Material-style {@code calendar} mode
    422      */
    423     @Deprecated
    424     public boolean getCalendarViewShown() {
    425         return mDelegate.getCalendarViewShown();
    426     }
    427 
    428     /**
    429      * Returns the {@link CalendarView} used by this picker.
    430      * <p>
    431      * <strong>Note:</strong> This method throws an
    432      * {@link UnsupportedOperationException} when the
    433      * {@link android.R.styleable#DatePicker_datePickerMode} attribute is set
    434      * to {@code calendar}.
    435      *
    436      * @return the calendar view
    437      * @see #getCalendarViewShown()
    438      * @deprecated Not supported by Material-style {@code calendar} mode
    439      * @throws UnsupportedOperationException if called when the picker is
    440      *         displayed in {@code calendar} mode
    441      */
    442     @Deprecated
    443     public CalendarView getCalendarView() {
    444         return mDelegate.getCalendarView();
    445     }
    446 
    447     /**
    448      * Sets whether the {@link CalendarView} is shown.
    449      * <p>
    450      * <strong>Note:</strong> Calling this method has no effect when the
    451      * {@link android.R.styleable#DatePicker_datePickerMode} attribute is set
    452      * to {@code calendar}.
    453      *
    454      * @param shown {@code true} to show the calendar view, {@code false} to
    455      *              hide it
    456      * @deprecated Not supported by Material-style {@code calendar} mode
    457      */
    458     @Deprecated
    459     public void setCalendarViewShown(boolean shown) {
    460         mDelegate.setCalendarViewShown(shown);
    461     }
    462 
    463     /**
    464      * Returns whether the spinners are shown.
    465      * <p>
    466      * <strong>Note:</strong> his method returns {@code false} when the
    467      * {@link android.R.styleable#DatePicker_datePickerMode} attribute is set
    468      * to {@code calendar}.
    469      *
    470      * @return {@code true} if the spinners are shown
    471      * @deprecated Not supported by Material-style {@code calendar} mode
    472      */
    473     @Deprecated
    474     public boolean getSpinnersShown() {
    475         return mDelegate.getSpinnersShown();
    476     }
    477 
    478     /**
    479      * Sets whether the spinners are shown.
    480      * <p>
    481      * Calling this method has no effect when the
    482      * {@link android.R.styleable#DatePicker_datePickerMode} attribute is set
    483      * to {@code calendar}.
    484      *
    485      * @param shown {@code true} to show the spinners, {@code false} to hide
    486      *              them
    487      * @deprecated Not supported by Material-style {@code calendar} mode
    488      */
    489     @Deprecated
    490     public void setSpinnersShown(boolean shown) {
    491         mDelegate.setSpinnersShown(shown);
    492     }
    493 
    494     @Override
    495     protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
    496         dispatchThawSelfOnly(container);
    497     }
    498 
    499     @Override
    500     protected Parcelable onSaveInstanceState() {
    501         Parcelable superState = super.onSaveInstanceState();
    502         return mDelegate.onSaveInstanceState(superState);
    503     }
    504 
    505     @Override
    506     protected void onRestoreInstanceState(Parcelable state) {
    507         BaseSavedState ss = (BaseSavedState) state;
    508         super.onRestoreInstanceState(ss.getSuperState());
    509         mDelegate.onRestoreInstanceState(ss);
    510     }
    511 
    512     /**
    513      * A delegate interface that defined the public API of the DatePicker. Allows different
    514      * DatePicker implementations. This would need to be implemented by the DatePicker delegates
    515      * for the real behavior.
    516      *
    517      * @hide
    518      */
    519     interface DatePickerDelegate {
    520         void init(int year, int monthOfYear, int dayOfMonth,
    521                   OnDateChangedListener onDateChangedListener);
    522 
    523         void setOnDateChangedListener(OnDateChangedListener onDateChangedListener);
    524         void setAutoFillChangeListener(OnDateChangedListener onDateChangedListener);
    525 
    526         void updateDate(int year, int month, int dayOfMonth);
    527         void updateDate(long date);
    528 
    529         int getYear();
    530         int getMonth();
    531         int getDayOfMonth();
    532         long getDate();
    533 
    534         void setFirstDayOfWeek(int firstDayOfWeek);
    535         int getFirstDayOfWeek();
    536 
    537         void setMinDate(long minDate);
    538         Calendar getMinDate();
    539 
    540         void setMaxDate(long maxDate);
    541         Calendar getMaxDate();
    542 
    543         void setEnabled(boolean enabled);
    544         boolean isEnabled();
    545 
    546         CalendarView getCalendarView();
    547 
    548         void setCalendarViewShown(boolean shown);
    549         boolean getCalendarViewShown();
    550 
    551         void setSpinnersShown(boolean shown);
    552         boolean getSpinnersShown();
    553 
    554         void setValidationCallback(ValidationCallback callback);
    555 
    556         void onConfigurationChanged(Configuration newConfig);
    557 
    558         Parcelable onSaveInstanceState(Parcelable superState);
    559         void onRestoreInstanceState(Parcelable state);
    560 
    561         boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event);
    562         void onPopulateAccessibilityEvent(AccessibilityEvent event);
    563     }
    564 
    565     /**
    566      * An abstract class which can be used as a start for DatePicker implementations
    567      */
    568     abstract static class AbstractDatePickerDelegate implements DatePickerDelegate {
    569         // The delegator
    570         protected DatePicker mDelegator;
    571 
    572         // The context
    573         protected Context mContext;
    574 
    575         protected Calendar mCurrentDate;
    576 
    577         // The current locale
    578         protected Locale mCurrentLocale;
    579 
    580         // Callbacks
    581         protected OnDateChangedListener mOnDateChangedListener;
    582         protected OnDateChangedListener mAutoFillChangeListener;
    583         protected ValidationCallback mValidationCallback;
    584 
    585         public AbstractDatePickerDelegate(DatePicker delegator, Context context) {
    586             mDelegator = delegator;
    587             mContext = context;
    588 
    589             setCurrentLocale(Locale.getDefault());
    590         }
    591 
    592         protected void setCurrentLocale(Locale locale) {
    593             if (!locale.equals(mCurrentLocale)) {
    594                 mCurrentLocale = locale;
    595                 onLocaleChanged(locale);
    596             }
    597         }
    598 
    599         @Override
    600         public void setOnDateChangedListener(OnDateChangedListener callback) {
    601             mOnDateChangedListener = callback;
    602         }
    603 
    604         @Override
    605         public void setAutoFillChangeListener(OnDateChangedListener callback) {
    606             mAutoFillChangeListener = callback;
    607         }
    608 
    609         @Override
    610         public void setValidationCallback(ValidationCallback callback) {
    611             mValidationCallback = callback;
    612         }
    613 
    614         @Override
    615         public void updateDate(long date) {
    616             Calendar cal = Calendar.getInstance(mCurrentLocale);
    617             cal.setTimeInMillis(date);
    618             updateDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
    619                     cal.get(Calendar.DAY_OF_MONTH));
    620         }
    621 
    622         @Override
    623         public long getDate() {
    624             return mCurrentDate.getTimeInMillis();
    625         }
    626 
    627         protected void onValidationChanged(boolean valid) {
    628             if (mValidationCallback != null) {
    629                 mValidationCallback.onValidationChanged(valid);
    630             }
    631         }
    632 
    633         protected void onLocaleChanged(Locale locale) {
    634             // Stub.
    635         }
    636 
    637         @Override
    638         public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
    639             event.getText().add(getFormattedCurrentDate());
    640         }
    641 
    642         protected String getFormattedCurrentDate() {
    643            return DateUtils.formatDateTime(mContext, mCurrentDate.getTimeInMillis(),
    644                    DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR
    645                            | DateUtils.FORMAT_SHOW_WEEKDAY);
    646         }
    647 
    648         /**
    649          * Class for managing state storing/restoring.
    650          */
    651         static class SavedState extends View.BaseSavedState {
    652             private final int mSelectedYear;
    653             private final int mSelectedMonth;
    654             private final int mSelectedDay;
    655             private final long mMinDate;
    656             private final long mMaxDate;
    657             private final int mCurrentView;
    658             private final int mListPosition;
    659             private final int mListPositionOffset;
    660 
    661             public SavedState(Parcelable superState, int year, int month, int day, long minDate,
    662                     long maxDate) {
    663                 this(superState, year, month, day, minDate, maxDate, 0, 0, 0);
    664             }
    665 
    666             /**
    667              * Constructor called from {@link DatePicker#onSaveInstanceState()}
    668              */
    669             public SavedState(Parcelable superState, int year, int month, int day, long minDate,
    670                     long maxDate, int currentView, int listPosition, int listPositionOffset) {
    671                 super(superState);
    672                 mSelectedYear = year;
    673                 mSelectedMonth = month;
    674                 mSelectedDay = day;
    675                 mMinDate = minDate;
    676                 mMaxDate = maxDate;
    677                 mCurrentView = currentView;
    678                 mListPosition = listPosition;
    679                 mListPositionOffset = listPositionOffset;
    680             }
    681 
    682             /**
    683              * Constructor called from {@link #CREATOR}
    684              */
    685             private SavedState(Parcel in) {
    686                 super(in);
    687                 mSelectedYear = in.readInt();
    688                 mSelectedMonth = in.readInt();
    689                 mSelectedDay = in.readInt();
    690                 mMinDate = in.readLong();
    691                 mMaxDate = in.readLong();
    692                 mCurrentView = in.readInt();
    693                 mListPosition = in.readInt();
    694                 mListPositionOffset = in.readInt();
    695             }
    696 
    697             @Override
    698             public void writeToParcel(Parcel dest, int flags) {
    699                 super.writeToParcel(dest, flags);
    700                 dest.writeInt(mSelectedYear);
    701                 dest.writeInt(mSelectedMonth);
    702                 dest.writeInt(mSelectedDay);
    703                 dest.writeLong(mMinDate);
    704                 dest.writeLong(mMaxDate);
    705                 dest.writeInt(mCurrentView);
    706                 dest.writeInt(mListPosition);
    707                 dest.writeInt(mListPositionOffset);
    708             }
    709 
    710             public int getSelectedDay() {
    711                 return mSelectedDay;
    712             }
    713 
    714             public int getSelectedMonth() {
    715                 return mSelectedMonth;
    716             }
    717 
    718             public int getSelectedYear() {
    719                 return mSelectedYear;
    720             }
    721 
    722             public long getMinDate() {
    723                 return mMinDate;
    724             }
    725 
    726             public long getMaxDate() {
    727                 return mMaxDate;
    728             }
    729 
    730             public int getCurrentView() {
    731                 return mCurrentView;
    732             }
    733 
    734             public int getListPosition() {
    735                 return mListPosition;
    736             }
    737 
    738             public int getListPositionOffset() {
    739                 return mListPositionOffset;
    740             }
    741 
    742             @SuppressWarnings("all")
    743             // suppress unused and hiding
    744             public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
    745 
    746                 public SavedState createFromParcel(Parcel in) {
    747                     return new SavedState(in);
    748                 }
    749 
    750                 public SavedState[] newArray(int size) {
    751                     return new SavedState[size];
    752                 }
    753             };
    754         }
    755     }
    756 
    757     /**
    758      * A callback interface for updating input validity when the date picker
    759      * when included into a dialog.
    760      *
    761      * @hide
    762      */
    763     public interface ValidationCallback {
    764         void onValidationChanged(boolean valid);
    765     }
    766 
    767     @Override
    768     public void dispatchProvideAutofillStructure(ViewStructure structure, int flags) {
    769         // This view is self-sufficient for autofill, so it needs to call
    770         // onProvideAutoFillStructure() to fill itself, but it does not need to call
    771         // dispatchProvideAutoFillStructure() to fill its children.
    772         structure.setAutofillId(getAutofillId());
    773         onProvideAutofillStructure(structure, flags);
    774     }
    775 
    776     @Override
    777     public void autofill(AutofillValue value) {
    778         if (!isEnabled()) return;
    779 
    780         if (!value.isDate()) {
    781             Log.w(LOG_TAG, value + " could not be autofilled into " + this);
    782             return;
    783         }
    784 
    785         mDelegate.updateDate(value.getDateValue());
    786     }
    787 
    788     @Override
    789     public @AutofillType int getAutofillType() {
    790         return isEnabled() ? AUTOFILL_TYPE_DATE : AUTOFILL_TYPE_NONE;
    791     }
    792 
    793     @Override
    794     public AutofillValue getAutofillValue() {
    795         return isEnabled() ? AutofillValue.forDate(mDelegate.getDate()) : null;
    796     }
    797 }
    798