• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.Nullable;
20 import android.content.Context;
21 import android.content.res.ColorStateList;
22 import android.content.res.Configuration;
23 import android.content.res.Resources;
24 import android.content.res.TypedArray;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 import android.text.format.DateFormat;
28 import android.text.format.DateUtils;
29 import android.util.AttributeSet;
30 import android.util.StateSet;
31 import android.view.HapticFeedbackConstants;
32 import android.view.LayoutInflater;
33 import android.view.View;
34 import android.view.View.OnClickListener;
35 import android.view.ViewGroup;
36 import android.view.accessibility.AccessibilityEvent;
37 import android.widget.DayPickerView.OnDaySelectedListener;
38 import android.widget.YearPickerView.OnYearSelectedListener;
39 
40 import com.android.internal.R;
41 
42 import java.text.SimpleDateFormat;
43 import java.util.Calendar;
44 import java.util.Locale;
45 
46 /**
47  * A delegate for picking up a date (day / month / year).
48  */
49 class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate {
50     private static final int USE_LOCALE = 0;
51 
52     private static final int UNINITIALIZED = -1;
53     private static final int VIEW_MONTH_DAY = 0;
54     private static final int VIEW_YEAR = 1;
55 
56     private static final int DEFAULT_START_YEAR = 1900;
57     private static final int DEFAULT_END_YEAR = 2100;
58 
59     private static final int ANIMATION_DURATION = 300;
60 
61     private static final int[] ATTRS_TEXT_COLOR = new int[] {
62             com.android.internal.R.attr.textColor};
63     private static final int[] ATTRS_DISABLED_ALPHA = new int[] {
64             com.android.internal.R.attr.disabledAlpha};
65 
66     private SimpleDateFormat mYearFormat;
67     private SimpleDateFormat mMonthDayFormat;
68 
69     // Top-level container.
70     private ViewGroup mContainer;
71 
72     // Header views.
73     private TextView mHeaderYear;
74     private TextView mHeaderMonthDay;
75 
76     // Picker views.
77     private ViewAnimator mAnimator;
78     private DayPickerView mDayPickerView;
79     private YearPickerView mYearPickerView;
80 
81     // Accessibility strings.
82     private String mSelectDay;
83     private String mSelectYear;
84 
85     private DatePicker.OnDateChangedListener mDateChangedListener;
86 
87     private int mCurrentView = UNINITIALIZED;
88 
89     private final Calendar mCurrentDate;
90     private final Calendar mTempDate;
91     private final Calendar mMinDate;
92     private final Calendar mMaxDate;
93 
94     private int mFirstDayOfWeek = USE_LOCALE;
95 
DatePickerCalendarDelegate(DatePicker delegator, Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)96     public DatePickerCalendarDelegate(DatePicker delegator, Context context, AttributeSet attrs,
97             int defStyleAttr, int defStyleRes) {
98         super(delegator, context);
99 
100         final Locale locale = mCurrentLocale;
101         mCurrentDate = Calendar.getInstance(locale);
102         mTempDate = Calendar.getInstance(locale);
103         mMinDate = Calendar.getInstance(locale);
104         mMaxDate = Calendar.getInstance(locale);
105 
106         mMinDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1);
107         mMaxDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31);
108 
109         final Resources res = mDelegator.getResources();
110         final TypedArray a = mContext.obtainStyledAttributes(attrs,
111                 R.styleable.DatePicker, defStyleAttr, defStyleRes);
112         final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
113                 Context.LAYOUT_INFLATER_SERVICE);
114         final int layoutResourceId = a.getResourceId(
115                 R.styleable.DatePicker_internalLayout, R.layout.date_picker_material);
116 
117         // Set up and attach container.
118         mContainer = (ViewGroup) inflater.inflate(layoutResourceId, mDelegator, false);
119         mDelegator.addView(mContainer);
120 
121         // Set up header views.
122         final ViewGroup header = (ViewGroup) mContainer.findViewById(R.id.date_picker_header);
123         mHeaderYear = (TextView) header.findViewById(R.id.date_picker_header_year);
124         mHeaderYear.setOnClickListener(mOnHeaderClickListener);
125         mHeaderMonthDay = (TextView) header.findViewById(R.id.date_picker_header_date);
126         mHeaderMonthDay.setOnClickListener(mOnHeaderClickListener);
127 
128         // For the sake of backwards compatibility, attempt to extract the text
129         // color from the header month text appearance. If it's set, we'll let
130         // that override the "real" header text color.
131         ColorStateList headerTextColor = null;
132 
133         @SuppressWarnings("deprecation")
134         final int monthHeaderTextAppearance = a.getResourceId(
135                 R.styleable.DatePicker_headerMonthTextAppearance, 0);
136         if (monthHeaderTextAppearance != 0) {
137             final TypedArray textAppearance = mContext.obtainStyledAttributes(null,
138                     ATTRS_TEXT_COLOR, 0, monthHeaderTextAppearance);
139             final ColorStateList legacyHeaderTextColor = textAppearance.getColorStateList(0);
140             headerTextColor = applyLegacyColorFixes(legacyHeaderTextColor);
141             textAppearance.recycle();
142         }
143 
144         if (headerTextColor == null) {
145             headerTextColor = a.getColorStateList(R.styleable.DatePicker_headerTextColor);
146         }
147 
148         if (headerTextColor != null) {
149             mHeaderYear.setTextColor(headerTextColor);
150             mHeaderMonthDay.setTextColor(headerTextColor);
151         }
152 
153         // Set up header background, if available.
154         if (a.hasValueOrEmpty(R.styleable.DatePicker_headerBackground)) {
155             header.setBackground(a.getDrawable(R.styleable.DatePicker_headerBackground));
156         }
157 
158         a.recycle();
159 
160         // Set up picker container.
161         mAnimator = (ViewAnimator) mContainer.findViewById(R.id.animator);
162 
163         // Set up day picker view.
164         mDayPickerView = (DayPickerView) mAnimator.findViewById(R.id.date_picker_day_picker);
165         mDayPickerView.setFirstDayOfWeek(mFirstDayOfWeek);
166         mDayPickerView.setMinDate(mMinDate.getTimeInMillis());
167         mDayPickerView.setMaxDate(mMaxDate.getTimeInMillis());
168         mDayPickerView.setDate(mCurrentDate.getTimeInMillis());
169         mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener);
170 
171         // Set up year picker view.
172         mYearPickerView = (YearPickerView) mAnimator.findViewById(R.id.date_picker_year_picker);
173         mYearPickerView.setRange(mMinDate, mMaxDate);
174         mYearPickerView.setDate(mCurrentDate.getTimeInMillis());
175         mYearPickerView.setOnYearSelectedListener(mOnYearSelectedListener);
176 
177         // Set up content descriptions.
178         mSelectDay = res.getString(R.string.select_day);
179         mSelectYear = res.getString(R.string.select_year);
180 
181         // Initialize for current locale. This also initializes the date, so no
182         // need to call onDateChanged.
183         onLocaleChanged(mCurrentLocale);
184 
185         setCurrentView(VIEW_MONTH_DAY);
186     }
187 
188     /**
189      * The legacy text color might have been poorly defined. Ensures that it
190      * has an appropriate activated state, using the selected state if one
191      * exists or modifying the default text color otherwise.
192      *
193      * @param color a legacy text color, or {@code null}
194      * @return a color state list with an appropriate activated state, or
195      *         {@code null} if a valid activated state could not be generated
196      */
197     @Nullable
applyLegacyColorFixes(@ullable ColorStateList color)198     private ColorStateList applyLegacyColorFixes(@Nullable ColorStateList color) {
199         if (color == null || color.hasState(R.attr.state_activated)) {
200             return color;
201         }
202 
203         final int activatedColor;
204         final int defaultColor;
205         if (color.hasState(R.attr.state_selected)) {
206             activatedColor = color.getColorForState(StateSet.get(
207                     StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_SELECTED), 0);
208             defaultColor = color.getColorForState(StateSet.get(
209                     StateSet.VIEW_STATE_ENABLED), 0);
210         } else {
211             activatedColor = color.getDefaultColor();
212 
213             // Generate a non-activated color using the disabled alpha.
214             final TypedArray ta = mContext.obtainStyledAttributes(ATTRS_DISABLED_ALPHA);
215             final float disabledAlpha = ta.getFloat(0, 0.30f);
216             defaultColor = multiplyAlphaComponent(activatedColor, disabledAlpha);
217         }
218 
219         if (activatedColor == 0 || defaultColor == 0) {
220             // We somehow failed to obtain the colors.
221             return null;
222         }
223 
224         final int[][] stateSet = new int[][] {{ R.attr.state_activated }, {}};
225         final int[] colors = new int[] { activatedColor, defaultColor };
226         return new ColorStateList(stateSet, colors);
227     }
228 
multiplyAlphaComponent(int color, float alphaMod)229     private int multiplyAlphaComponent(int color, float alphaMod) {
230         final int srcRgb = color & 0xFFFFFF;
231         final int srcAlpha = (color >> 24) & 0xFF;
232         final int dstAlpha = (int) (srcAlpha * alphaMod + 0.5f);
233         return srcRgb | (dstAlpha << 24);
234     }
235 
236     /**
237      * Listener called when the user selects a day in the day picker view.
238      */
239     private final OnDaySelectedListener mOnDaySelectedListener = new OnDaySelectedListener() {
240         @Override
241         public void onDaySelected(DayPickerView view, Calendar day) {
242             mCurrentDate.setTimeInMillis(day.getTimeInMillis());
243             onDateChanged(true, true);
244         }
245     };
246 
247     /**
248      * Listener called when the user selects a year in the year picker view.
249      */
250     private final OnYearSelectedListener mOnYearSelectedListener = new OnYearSelectedListener() {
251         @Override
252         public void onYearChanged(YearPickerView view, int year) {
253             // If the newly selected month / year does not contain the
254             // currently selected day number, change the selected day number
255             // to the last day of the selected month or year.
256             // e.g. Switching from Mar to Apr when Mar 31 is selected -> Apr 30
257             // e.g. Switching from 2012 to 2013 when Feb 29, 2012 is selected -> Feb 28, 2013
258             final int day = mCurrentDate.get(Calendar.DAY_OF_MONTH);
259             final int month = mCurrentDate.get(Calendar.MONTH);
260             final int daysInMonth = getDaysInMonth(month, year);
261             if (day > daysInMonth) {
262                 mCurrentDate.set(Calendar.DAY_OF_MONTH, daysInMonth);
263             }
264 
265             mCurrentDate.set(Calendar.YEAR, year);
266             onDateChanged(true, true);
267 
268             // Automatically switch to day picker.
269             setCurrentView(VIEW_MONTH_DAY);
270         }
271     };
272 
273     /**
274      * Listener called when the user clicks on a header item.
275      */
276     private final OnClickListener mOnHeaderClickListener = new OnClickListener() {
277         @Override
278         public void onClick(View v) {
279             tryVibrate();
280 
281             switch (v.getId()) {
282                 case R.id.date_picker_header_year:
283                     setCurrentView(VIEW_YEAR);
284                     break;
285                 case R.id.date_picker_header_date:
286                     setCurrentView(VIEW_MONTH_DAY);
287                     break;
288             }
289         }
290     };
291 
292     @Override
onLocaleChanged(Locale locale)293     protected void onLocaleChanged(Locale locale) {
294         final TextView headerYear = mHeaderYear;
295         if (headerYear == null) {
296             // Abort, we haven't initialized yet. This method will get called
297             // again later after everything has been set up.
298             return;
299         }
300 
301         // Update the date formatter.
302         final String datePattern = DateFormat.getBestDateTimePattern(locale, "EMMMd");
303         mMonthDayFormat = new SimpleDateFormat(datePattern, locale);
304         mYearFormat = new SimpleDateFormat("y", locale);
305 
306         // Update the header text.
307         onCurrentDateChanged(false);
308     }
309 
onCurrentDateChanged(boolean announce)310     private void onCurrentDateChanged(boolean announce) {
311         if (mHeaderYear == null) {
312             // Abort, we haven't initialized yet. This method will get called
313             // again later after everything has been set up.
314             return;
315         }
316 
317         final String year = mYearFormat.format(mCurrentDate.getTime());
318         mHeaderYear.setText(year);
319 
320         final String monthDay = mMonthDayFormat.format(mCurrentDate.getTime());
321         mHeaderMonthDay.setText(monthDay);
322 
323         // TODO: This should use live regions.
324         if (announce) {
325             final long millis = mCurrentDate.getTimeInMillis();
326             final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
327             final String fullDateText = DateUtils.formatDateTime(mContext, millis, flags);
328             mAnimator.announceForAccessibility(fullDateText);
329         }
330     }
331 
setCurrentView(final int viewIndex)332     private void setCurrentView(final int viewIndex) {
333         switch (viewIndex) {
334             case VIEW_MONTH_DAY:
335                 mDayPickerView.setDate(mCurrentDate.getTimeInMillis());
336 
337                 if (mCurrentView != viewIndex) {
338                     mHeaderMonthDay.setActivated(true);
339                     mHeaderYear.setActivated(false);
340                     mAnimator.setDisplayedChild(VIEW_MONTH_DAY);
341                     mCurrentView = viewIndex;
342                 }
343 
344                 mAnimator.announceForAccessibility(mSelectDay);
345                 break;
346             case VIEW_YEAR:
347                 mYearPickerView.setDate(mCurrentDate.getTimeInMillis());
348 
349                 if (mCurrentView != viewIndex) {
350                     mHeaderMonthDay.setActivated(false);
351                     mHeaderYear.setActivated(true);
352                     mAnimator.setDisplayedChild(VIEW_YEAR);
353                     mCurrentView = viewIndex;
354                 }
355 
356                 mAnimator.announceForAccessibility(mSelectYear);
357                 break;
358         }
359     }
360 
361     @Override
init(int year, int monthOfYear, int dayOfMonth, DatePicker.OnDateChangedListener callBack)362     public void init(int year, int monthOfYear, int dayOfMonth,
363             DatePicker.OnDateChangedListener callBack) {
364         mCurrentDate.set(Calendar.YEAR, year);
365         mCurrentDate.set(Calendar.MONTH, monthOfYear);
366         mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
367 
368         mDateChangedListener = callBack;
369 
370         onDateChanged(false, false);
371     }
372 
373     @Override
updateDate(int year, int month, int dayOfMonth)374     public void updateDate(int year, int month, int dayOfMonth) {
375         mCurrentDate.set(Calendar.YEAR, year);
376         mCurrentDate.set(Calendar.MONTH, month);
377         mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
378 
379         onDateChanged(false, true);
380     }
381 
onDateChanged(boolean fromUser, boolean callbackToClient)382     private void onDateChanged(boolean fromUser, boolean callbackToClient) {
383         final int year = mCurrentDate.get(Calendar.YEAR);
384 
385         if (callbackToClient && mDateChangedListener != null) {
386             final int monthOfYear = mCurrentDate.get(Calendar.MONTH);
387             final int dayOfMonth = mCurrentDate.get(Calendar.DAY_OF_MONTH);
388             mDateChangedListener.onDateChanged(mDelegator, year, monthOfYear, dayOfMonth);
389         }
390 
391         mDayPickerView.setDate(mCurrentDate.getTimeInMillis());
392         mYearPickerView.setYear(year);
393 
394         onCurrentDateChanged(fromUser);
395 
396         if (fromUser) {
397             tryVibrate();
398         }
399     }
400 
401     @Override
getYear()402     public int getYear() {
403         return mCurrentDate.get(Calendar.YEAR);
404     }
405 
406     @Override
getMonth()407     public int getMonth() {
408         return mCurrentDate.get(Calendar.MONTH);
409     }
410 
411     @Override
getDayOfMonth()412     public int getDayOfMonth() {
413         return mCurrentDate.get(Calendar.DAY_OF_MONTH);
414     }
415 
416     @Override
setMinDate(long minDate)417     public void setMinDate(long minDate) {
418         mTempDate.setTimeInMillis(minDate);
419         if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR)
420                 && mTempDate.get(Calendar.DAY_OF_YEAR) != mMinDate.get(Calendar.DAY_OF_YEAR)) {
421             return;
422         }
423         if (mCurrentDate.before(mTempDate)) {
424             mCurrentDate.setTimeInMillis(minDate);
425             onDateChanged(false, true);
426         }
427         mMinDate.setTimeInMillis(minDate);
428         mDayPickerView.setMinDate(minDate);
429         mYearPickerView.setRange(mMinDate, mMaxDate);
430     }
431 
432     @Override
getMinDate()433     public Calendar getMinDate() {
434         return mMinDate;
435     }
436 
437     @Override
setMaxDate(long maxDate)438     public void setMaxDate(long maxDate) {
439         mTempDate.setTimeInMillis(maxDate);
440         if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)
441                 && mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate.get(Calendar.DAY_OF_YEAR)) {
442             return;
443         }
444         if (mCurrentDate.after(mTempDate)) {
445             mCurrentDate.setTimeInMillis(maxDate);
446             onDateChanged(false, true);
447         }
448         mMaxDate.setTimeInMillis(maxDate);
449         mDayPickerView.setMaxDate(maxDate);
450         mYearPickerView.setRange(mMinDate, mMaxDate);
451     }
452 
453     @Override
getMaxDate()454     public Calendar getMaxDate() {
455         return mMaxDate;
456     }
457 
458     @Override
setFirstDayOfWeek(int firstDayOfWeek)459     public void setFirstDayOfWeek(int firstDayOfWeek) {
460         mFirstDayOfWeek = firstDayOfWeek;
461 
462         mDayPickerView.setFirstDayOfWeek(firstDayOfWeek);
463     }
464 
465     @Override
getFirstDayOfWeek()466     public int getFirstDayOfWeek() {
467         if (mFirstDayOfWeek != USE_LOCALE) {
468             return mFirstDayOfWeek;
469         }
470         return mCurrentDate.getFirstDayOfWeek();
471     }
472 
473     @Override
setEnabled(boolean enabled)474     public void setEnabled(boolean enabled) {
475         mContainer.setEnabled(enabled);
476         mDayPickerView.setEnabled(enabled);
477         mYearPickerView.setEnabled(enabled);
478         mHeaderYear.setEnabled(enabled);
479         mHeaderMonthDay.setEnabled(enabled);
480     }
481 
482     @Override
isEnabled()483     public boolean isEnabled() {
484         return mContainer.isEnabled();
485     }
486 
487     @Override
getCalendarView()488     public CalendarView getCalendarView() {
489         throw new UnsupportedOperationException("Not supported by calendar-mode DatePicker");
490     }
491 
492     @Override
setCalendarViewShown(boolean shown)493     public void setCalendarViewShown(boolean shown) {
494         // No-op for compatibility with the old DatePicker.
495     }
496 
497     @Override
getCalendarViewShown()498     public boolean getCalendarViewShown() {
499         return false;
500     }
501 
502     @Override
setSpinnersShown(boolean shown)503     public void setSpinnersShown(boolean shown) {
504         // No-op for compatibility with the old DatePicker.
505     }
506 
507     @Override
getSpinnersShown()508     public boolean getSpinnersShown() {
509         return false;
510     }
511 
512     @Override
onConfigurationChanged(Configuration newConfig)513     public void onConfigurationChanged(Configuration newConfig) {
514         setCurrentLocale(newConfig.locale);
515     }
516 
517     @Override
onSaveInstanceState(Parcelable superState)518     public Parcelable onSaveInstanceState(Parcelable superState) {
519         final int year = mCurrentDate.get(Calendar.YEAR);
520         final int month = mCurrentDate.get(Calendar.MONTH);
521         final int day = mCurrentDate.get(Calendar.DAY_OF_MONTH);
522 
523         int listPosition = -1;
524         int listPositionOffset = -1;
525 
526         if (mCurrentView == VIEW_MONTH_DAY) {
527             listPosition = mDayPickerView.getMostVisiblePosition();
528         } else if (mCurrentView == VIEW_YEAR) {
529             listPosition = mYearPickerView.getFirstVisiblePosition();
530             listPositionOffset = mYearPickerView.getFirstPositionOffset();
531         }
532 
533         return new SavedState(superState, year, month, day, mMinDate.getTimeInMillis(),
534                 mMaxDate.getTimeInMillis(), mCurrentView, listPosition, listPositionOffset);
535     }
536 
537     @Override
onRestoreInstanceState(Parcelable state)538     public void onRestoreInstanceState(Parcelable state) {
539         final SavedState ss = (SavedState) state;
540 
541         // TODO: Move instance state into DayPickerView, YearPickerView.
542         mCurrentDate.set(ss.getSelectedYear(), ss.getSelectedMonth(), ss.getSelectedDay());
543         mMinDate.setTimeInMillis(ss.getMinDate());
544         mMaxDate.setTimeInMillis(ss.getMaxDate());
545 
546         onCurrentDateChanged(false);
547 
548         final int currentView = ss.getCurrentView();
549         setCurrentView(currentView);
550 
551         final int listPosition = ss.getListPosition();
552         if (listPosition != -1) {
553             if (currentView == VIEW_MONTH_DAY) {
554                 mDayPickerView.setPosition(listPosition);
555             } else if (currentView == VIEW_YEAR) {
556                 final int listPositionOffset = ss.getListPositionOffset();
557                 mYearPickerView.setSelectionFromTop(listPosition, listPositionOffset);
558             }
559         }
560     }
561 
562     @Override
dispatchPopulateAccessibilityEvent(AccessibilityEvent event)563     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
564         onPopulateAccessibilityEvent(event);
565         return true;
566     }
567 
568     @Override
onPopulateAccessibilityEvent(AccessibilityEvent event)569     public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
570         event.getText().add(mCurrentDate.getTime().toString());
571     }
572 
getAccessibilityClassName()573     public CharSequence getAccessibilityClassName() {
574         return DatePicker.class.getName();
575     }
576 
getDaysInMonth(int month, int year)577     public static int getDaysInMonth(int month, int year) {
578         switch (month) {
579             case Calendar.JANUARY:
580             case Calendar.MARCH:
581             case Calendar.MAY:
582             case Calendar.JULY:
583             case Calendar.AUGUST:
584             case Calendar.OCTOBER:
585             case Calendar.DECEMBER:
586                 return 31;
587             case Calendar.APRIL:
588             case Calendar.JUNE:
589             case Calendar.SEPTEMBER:
590             case Calendar.NOVEMBER:
591                 return 30;
592             case Calendar.FEBRUARY:
593                 return (year % 4 == 0) ? 29 : 28;
594             default:
595                 throw new IllegalArgumentException("Invalid Month");
596         }
597     }
598 
tryVibrate()599     private void tryVibrate() {
600         mDelegator.performHapticFeedback(HapticFeedbackConstants.CALENDAR_DATE);
601     }
602 
603     /**
604      * Class for managing state storing/restoring.
605      */
606     private static class SavedState extends View.BaseSavedState {
607         private final int mSelectedYear;
608         private final int mSelectedMonth;
609         private final int mSelectedDay;
610         private final long mMinDate;
611         private final long mMaxDate;
612         private final int mCurrentView;
613         private final int mListPosition;
614         private final int mListPositionOffset;
615 
616         /**
617          * Constructor called from {@link DatePicker#onSaveInstanceState()}
618          */
SavedState(Parcelable superState, int year, int month, int day, long minDate, long maxDate, int currentView, int listPosition, int listPositionOffset)619         private SavedState(Parcelable superState, int year, int month, int day,
620                 long minDate, long maxDate, int currentView, int listPosition,
621                 int listPositionOffset) {
622             super(superState);
623             mSelectedYear = year;
624             mSelectedMonth = month;
625             mSelectedDay = day;
626             mMinDate = minDate;
627             mMaxDate = maxDate;
628             mCurrentView = currentView;
629             mListPosition = listPosition;
630             mListPositionOffset = listPositionOffset;
631         }
632 
633         /**
634          * Constructor called from {@link #CREATOR}
635          */
SavedState(Parcel in)636         private SavedState(Parcel in) {
637             super(in);
638             mSelectedYear = in.readInt();
639             mSelectedMonth = in.readInt();
640             mSelectedDay = in.readInt();
641             mMinDate = in.readLong();
642             mMaxDate = in.readLong();
643             mCurrentView = in.readInt();
644             mListPosition = in.readInt();
645             mListPositionOffset = in.readInt();
646         }
647 
648         @Override
writeToParcel(Parcel dest, int flags)649         public void writeToParcel(Parcel dest, int flags) {
650             super.writeToParcel(dest, flags);
651             dest.writeInt(mSelectedYear);
652             dest.writeInt(mSelectedMonth);
653             dest.writeInt(mSelectedDay);
654             dest.writeLong(mMinDate);
655             dest.writeLong(mMaxDate);
656             dest.writeInt(mCurrentView);
657             dest.writeInt(mListPosition);
658             dest.writeInt(mListPositionOffset);
659         }
660 
getSelectedDay()661         public int getSelectedDay() {
662             return mSelectedDay;
663         }
664 
getSelectedMonth()665         public int getSelectedMonth() {
666             return mSelectedMonth;
667         }
668 
getSelectedYear()669         public int getSelectedYear() {
670             return mSelectedYear;
671         }
672 
getMinDate()673         public long getMinDate() {
674             return mMinDate;
675         }
676 
getMaxDate()677         public long getMaxDate() {
678             return mMaxDate;
679         }
680 
getCurrentView()681         public int getCurrentView() {
682             return mCurrentView;
683         }
684 
getListPosition()685         public int getListPosition() {
686             return mListPosition;
687         }
688 
getListPositionOffset()689         public int getListPositionOffset() {
690             return mListPositionOffset;
691         }
692 
693         @SuppressWarnings("all")
694         // suppress unused and hiding
695         public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
696 
697             public SavedState createFromParcel(Parcel in) {
698                 return new SavedState(in);
699             }
700 
701             public SavedState[] newArray(int size) {
702                 return new SavedState[size];
703             }
704         };
705     }
706 }
707