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