DatePicker.java revision a53efe9923bedab4fe5d578f32eaff308e5b9e76
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 17package android.widget; 18 19import android.annotation.Widget; 20import android.content.Context; 21import android.content.res.Configuration; 22import android.content.res.TypedArray; 23import android.os.Parcel; 24import android.os.Parcelable; 25import android.text.TextUtils; 26import android.text.format.DateFormat; 27import android.text.format.DateUtils; 28import android.util.AttributeSet; 29import android.util.Log; 30import android.util.SparseArray; 31import android.view.LayoutInflater; 32import android.view.accessibility.AccessibilityEvent; 33import android.view.accessibility.AccessibilityManager; 34import android.view.inputmethod.EditorInfo; 35import android.widget.NumberPicker.OnValueChangeListener; 36 37import com.android.internal.R; 38 39import java.text.ParseException; 40import java.text.SimpleDateFormat; 41import java.util.Arrays; 42import java.util.Calendar; 43import java.util.Locale; 44import java.util.TimeZone; 45 46/** 47 * This class is a widget for selecting a date. The date can be selected by a 48 * year, month, and day spinners or a {@link CalendarView}. The set of spinners 49 * and the calendar view are automatically synchronized. The client can 50 * customize whether only the spinners, or only the calendar view, or both to be 51 * displayed. Also the minimal and maximal date from which dates to be selected 52 * can be customized. 53 * <p> 54 * See the <a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Date 55 * Picker tutorial</a>. 56 * </p> 57 * <p> 58 * For a dialog using this view, see {@link android.app.DatePickerDialog}. 59 * </p> 60 * 61 * @attr ref android.R.styleable#DatePicker_startYear 62 * @attr ref android.R.styleable#DatePicker_endYear 63 * @attr ref android.R.styleable#DatePicker_maxDate 64 * @attr ref android.R.styleable#DatePicker_minDate 65 * @attr ref android.R.styleable#DatePicker_spinnersShown 66 * @attr ref android.R.styleable#DatePicker_calendarViewShown 67 */ 68@Widget 69public class DatePicker extends FrameLayout { 70 71 private static final String LOG_TAG = DatePicker.class.getSimpleName(); 72 73 private static final String DATE_FORMAT = "MM/dd/yyyy"; 74 75 private static final int DEFAULT_START_YEAR = 1900; 76 77 private static final int DEFAULT_END_YEAR = 2100; 78 79 private static final boolean DEFAULT_CALENDAR_VIEW_SHOWN = true; 80 81 private static final boolean DEFAULT_SPINNERS_SHOWN = true; 82 83 private static final boolean DEFAULT_ENABLED_STATE = true; 84 85 private final LinearLayout mSpinners; 86 87 private final NumberPicker mDaySpinner; 88 89 private final NumberPicker mMonthSpinner; 90 91 private final NumberPicker mYearSpinner; 92 93 private final CalendarView mCalendarView; 94 95 private Locale mCurrentLocale; 96 97 private OnDateChangedListener mOnDateChangedListener; 98 99 private String[] mShortMonths; 100 101 private final java.text.DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT); 102 103 private int mNumberOfMonths; 104 105 private Calendar mTempDate; 106 107 private Calendar mMinDate; 108 109 private Calendar mMaxDate; 110 111 private Calendar mCurrentDate; 112 113 private boolean mIsEnabled = DEFAULT_ENABLED_STATE; 114 115 /** 116 * The callback used to indicate the user changes\d the date. 117 */ 118 public interface OnDateChangedListener { 119 120 /** 121 * Called upon a date change. 122 * 123 * @param view The view associated with this listener. 124 * @param year The year that was set. 125 * @param monthOfYear The month that was set (0-11) for compatibility 126 * with {@link java.util.Calendar}. 127 * @param dayOfMonth The day of the month that was set. 128 */ 129 void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth); 130 } 131 132 public DatePicker(Context context) { 133 this(context, null); 134 } 135 136 public DatePicker(Context context, AttributeSet attrs) { 137 this(context, attrs, R.attr.datePickerStyle); 138 } 139 140 public DatePicker(Context context, AttributeSet attrs, int defStyle) { 141 super(context, attrs, defStyle); 142 143 // initialization based on locale 144 setCurrentLocale(Locale.getDefault()); 145 146 TypedArray attributesArray = context.obtainStyledAttributes(attrs, R.styleable.DatePicker, 147 defStyle, 0); 148 boolean spinnersShown = attributesArray.getBoolean(R.styleable.DatePicker_spinnersShown, 149 DEFAULT_SPINNERS_SHOWN); 150 boolean calendarViewShown = attributesArray.getBoolean( 151 R.styleable.DatePicker_calendarViewShown, DEFAULT_CALENDAR_VIEW_SHOWN); 152 int startYear = attributesArray.getInt(R.styleable.DatePicker_startYear, 153 DEFAULT_START_YEAR); 154 int endYear = attributesArray.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR); 155 String minDate = attributesArray.getString(R.styleable.DatePicker_minDate); 156 String maxDate = attributesArray.getString(R.styleable.DatePicker_maxDate); 157 int layoutResourceId = attributesArray.getResourceId(R.styleable.DatePicker_layout, 158 R.layout.date_picker); 159 attributesArray.recycle(); 160 161 LayoutInflater inflater = (LayoutInflater) context 162 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 163 inflater.inflate(layoutResourceId, this, true); 164 165 OnValueChangeListener onChangeListener = new OnValueChangeListener() { 166 public void onValueChange(NumberPicker picker, int oldVal, int newVal) { 167 mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis()); 168 // take care of wrapping of days and months to update greater fields 169 if (picker == mDaySpinner) { 170 int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH); 171 if (oldVal == maxDayOfMonth && newVal == 1) { 172 mTempDate.add(Calendar.DAY_OF_MONTH, 1); 173 } else if (oldVal == 1 && newVal == maxDayOfMonth) { 174 mTempDate.add(Calendar.DAY_OF_MONTH, -1); 175 } else { 176 mTempDate.add(Calendar.DAY_OF_MONTH, newVal - oldVal); 177 } 178 } else if (picker == mMonthSpinner) { 179 if (oldVal == 11 && newVal == 0) { 180 mTempDate.add(Calendar.MONTH, 1); 181 } else if (oldVal == 0 && newVal == 11) { 182 mTempDate.add(Calendar.MONTH, -1); 183 } else { 184 mTempDate.add(Calendar.MONTH, newVal - oldVal); 185 } 186 } else if (picker == mYearSpinner) { 187 mTempDate.set(Calendar.YEAR, newVal); 188 } else { 189 throw new IllegalArgumentException(); 190 } 191 // now set the date to the adjusted one 192 setDate(mTempDate.get(Calendar.YEAR), mTempDate.get(Calendar.MONTH), 193 mTempDate.get(Calendar.DAY_OF_MONTH)); 194 updateSpinners(); 195 updateCalendarView(); 196 notifyDateChanged(); 197 } 198 }; 199 200 mSpinners = (LinearLayout) findViewById(R.id.pickers); 201 202 // calendar view day-picker 203 mCalendarView = (CalendarView) findViewById(R.id.calendar_view); 204 mCalendarView.setOnDateChangeListener(new CalendarView.OnDateChangeListener() { 205 public void onSelectedDayChange(CalendarView view, int year, int month, int monthDay) { 206 setDate(year, month, monthDay); 207 updateSpinners(); 208 notifyDateChanged(); 209 } 210 }); 211 212 // day 213 mDaySpinner = (NumberPicker) findViewById(R.id.day); 214 mDaySpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER); 215 mDaySpinner.setOnLongPressUpdateInterval(100); 216 mDaySpinner.setOnValueChangedListener(onChangeListener); 217 218 // month 219 mMonthSpinner = (NumberPicker) findViewById(R.id.month); 220 mMonthSpinner.setMinValue(0); 221 mMonthSpinner.setMaxValue(mNumberOfMonths - 1); 222 mMonthSpinner.setDisplayedValues(mShortMonths); 223 mMonthSpinner.setOnLongPressUpdateInterval(200); 224 mMonthSpinner.setOnValueChangedListener(onChangeListener); 225 226 // year 227 mYearSpinner = (NumberPicker) findViewById(R.id.year); 228 mYearSpinner.setOnLongPressUpdateInterval(100); 229 mYearSpinner.setOnValueChangedListener(onChangeListener); 230 231 // show only what the user required but make sure we 232 // show something and the spinners have higher priority 233 if (!spinnersShown && !calendarViewShown) { 234 setSpinnersShown(true); 235 } else { 236 setSpinnersShown(spinnersShown); 237 setCalendarViewShown(calendarViewShown); 238 } 239 240 // set the min date giving priority of the minDate over startYear 241 mTempDate.clear(); 242 if (!TextUtils.isEmpty(minDate)) { 243 if (!parseDate(minDate, mTempDate)) { 244 mTempDate.set(startYear, 0, 1); 245 } 246 } else { 247 mTempDate.set(startYear, 0, 1); 248 } 249 setMinDate(mTempDate.getTimeInMillis()); 250 251 // set the max date giving priority of the maxDate over endYear 252 mTempDate.clear(); 253 if (!TextUtils.isEmpty(maxDate)) { 254 if (!parseDate(maxDate, mTempDate)) { 255 mTempDate.set(endYear, 11, 31); 256 } 257 } else { 258 mTempDate.set(endYear, 11, 31); 259 } 260 setMaxDate(mTempDate.getTimeInMillis()); 261 262 // initialize to current date 263 mCurrentDate.setTimeInMillis(System.currentTimeMillis()); 264 init(mCurrentDate.get(Calendar.YEAR), mCurrentDate.get(Calendar.MONTH), mCurrentDate 265 .get(Calendar.DAY_OF_MONTH), null); 266 267 // re-order the number spinners to match the current date format 268 reorderSpinners(); 269 270 // set content descriptions 271 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 272 setContentDescriptions(); 273 } 274 } 275 276 /** 277 * Gets the minimal date supported by this {@link DatePicker} in 278 * milliseconds since January 1, 1970 00:00:00 in 279 * {@link TimeZone#getDefault()} time zone. 280 * <p> 281 * Note: The default minimal date is 01/01/1900. 282 * <p> 283 * 284 * @return The minimal supported date. 285 */ 286 public long getMinDate() { 287 return mCalendarView.getMinDate(); 288 } 289 290 /** 291 * Sets the minimal date supported by this {@link NumberPicker} in 292 * milliseconds since January 1, 1970 00:00:00 in 293 * {@link TimeZone#getDefault()} time zone. 294 * 295 * @param minDate The minimal supported date. 296 */ 297 public void setMinDate(long minDate) { 298 mTempDate.setTimeInMillis(minDate); 299 if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR) 300 && mTempDate.get(Calendar.DAY_OF_YEAR) != mMinDate.get(Calendar.DAY_OF_YEAR)) { 301 return; 302 } 303 mMinDate.setTimeInMillis(minDate); 304 mCalendarView.setMinDate(minDate); 305 if (mCurrentDate.before(mMinDate)) { 306 mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis()); 307 updateCalendarView(); 308 } 309 updateSpinners(); 310 } 311 312 /** 313 * Gets 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 * <p> 317 * Note: The default maximal date is 12/31/2100. 318 * <p> 319 * 320 * @return The maximal supported date. 321 */ 322 public long getMaxDate() { 323 return mCalendarView.getMaxDate(); 324 } 325 326 /** 327 * Sets the maximal date supported by this {@link DatePicker} in 328 * milliseconds since January 1, 1970 00:00:00 in 329 * {@link TimeZone#getDefault()} time zone. 330 * 331 * @param maxDate The maximal supported date. 332 */ 333 public void setMaxDate(long maxDate) { 334 mTempDate.setTimeInMillis(maxDate); 335 if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR) 336 && mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate.get(Calendar.DAY_OF_YEAR)) { 337 return; 338 } 339 mMaxDate.setTimeInMillis(maxDate); 340 mCalendarView.setMaxDate(maxDate); 341 if (mCurrentDate.after(mMaxDate)) { 342 mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis()); 343 updateCalendarView(); 344 } 345 updateSpinners(); 346 } 347 348 @Override 349 public void setEnabled(boolean enabled) { 350 if (mIsEnabled == enabled) { 351 return; 352 } 353 super.setEnabled(enabled); 354 mDaySpinner.setEnabled(enabled); 355 mMonthSpinner.setEnabled(enabled); 356 mYearSpinner.setEnabled(enabled); 357 mCalendarView.setEnabled(enabled); 358 mIsEnabled = enabled; 359 } 360 361 @Override 362 public boolean isEnabled() { 363 return mIsEnabled; 364 } 365 366 @Override 367 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 368 onPopulateAccessibilityEvent(event); 369 return true; 370 } 371 372 @Override 373 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 374 super.onPopulateAccessibilityEvent(event); 375 376 final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR; 377 String selectedDateUtterance = DateUtils.formatDateTime(mContext, 378 mCurrentDate.getTimeInMillis(), flags); 379 event.getText().add(selectedDateUtterance); 380 } 381 382 @Override 383 protected void onConfigurationChanged(Configuration newConfig) { 384 super.onConfigurationChanged(newConfig); 385 setCurrentLocale(newConfig.locale); 386 } 387 388 /** 389 * Gets whether the {@link CalendarView} is shown. 390 * 391 * @return True if the calendar view is shown. 392 * @see #getCalendarView() 393 */ 394 public boolean getCalendarViewShown() { 395 return mCalendarView.isShown(); 396 } 397 398 /** 399 * Gets the {@link CalendarView}. 400 * 401 * @return The calendar view. 402 * @see #getCalendarViewShown() 403 */ 404 public CalendarView getCalendarView () { 405 return mCalendarView; 406 } 407 408 /** 409 * Sets whether the {@link CalendarView} is shown. 410 * 411 * @param shown True if the calendar view is to be shown. 412 */ 413 public void setCalendarViewShown(boolean shown) { 414 mCalendarView.setVisibility(shown ? VISIBLE : GONE); 415 } 416 417 /** 418 * Gets whether the spinners are shown. 419 * 420 * @return True if the spinners are shown. 421 */ 422 public boolean getSpinnersShown() { 423 return mSpinners.isShown(); 424 } 425 426 /** 427 * Sets whether the spinners are shown. 428 * 429 * @param shown True if the spinners are to be shown. 430 */ 431 public void setSpinnersShown(boolean shown) { 432 mSpinners.setVisibility(shown ? VISIBLE : GONE); 433 } 434 435 /** 436 * Sets the current locale. 437 * 438 * @param locale The current locale. 439 */ 440 private void setCurrentLocale(Locale locale) { 441 if (locale.equals(mCurrentLocale)) { 442 return; 443 } 444 445 mCurrentLocale = locale; 446 447 mTempDate = getCalendarForLocale(mTempDate, locale); 448 mMinDate = getCalendarForLocale(mMinDate, locale); 449 mMaxDate = getCalendarForLocale(mMaxDate, locale); 450 mCurrentDate = getCalendarForLocale(mCurrentDate, locale); 451 452 mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1; 453 mShortMonths = new String[mNumberOfMonths]; 454 for (int i = 0; i < mNumberOfMonths; i++) { 455 mShortMonths[i] = DateUtils.getMonthString(Calendar.JANUARY + i, 456 DateUtils.LENGTH_MEDIUM); 457 } 458 } 459 460 /** 461 * Gets a calendar for locale bootstrapped with the value of a given calendar. 462 * 463 * @param oldCalendar The old calendar. 464 * @param locale The locale. 465 */ 466 private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) { 467 if (oldCalendar == null) { 468 return Calendar.getInstance(locale); 469 } else { 470 final long currentTimeMillis = oldCalendar.getTimeInMillis(); 471 Calendar newCalendar = Calendar.getInstance(locale); 472 newCalendar.setTimeInMillis(currentTimeMillis); 473 return newCalendar; 474 } 475 } 476 477 /** 478 * Reorders the spinners according to the date format that is 479 * explicitly set by the user and if no such is set fall back 480 * to the current locale's default format. 481 */ 482 private void reorderSpinners() { 483 mSpinners.removeAllViews(); 484 char[] order = DateFormat.getDateFormatOrder(getContext()); 485 final int spinnerCount = order.length; 486 for (int i = 0; i < spinnerCount; i++) { 487 switch (order[i]) { 488 case DateFormat.DATE: 489 mSpinners.addView(mDaySpinner); 490 setImeOptions(mDaySpinner, spinnerCount, i); 491 break; 492 case DateFormat.MONTH: 493 mSpinners.addView(mMonthSpinner); 494 setImeOptions(mMonthSpinner, spinnerCount, i); 495 break; 496 case DateFormat.YEAR: 497 mSpinners.addView(mYearSpinner); 498 setImeOptions(mYearSpinner, spinnerCount, i); 499 break; 500 default: 501 throw new IllegalArgumentException(); 502 } 503 } 504 } 505 506 /** 507 * Updates the current date. 508 * 509 * @param year The year. 510 * @param month The month which is <strong>starting from zero</strong>. 511 * @param dayOfMonth The day of the month. 512 */ 513 public void updateDate(int year, int month, int dayOfMonth) { 514 if (!isNewDate(year, month, dayOfMonth)) { 515 return; 516 } 517 setDate(year, month, dayOfMonth); 518 updateSpinners(); 519 updateCalendarView(); 520 notifyDateChanged(); 521 } 522 523 // Override so we are in complete control of save / restore for this widget. 524 @Override 525 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 526 dispatchThawSelfOnly(container); 527 } 528 529 @Override 530 protected Parcelable onSaveInstanceState() { 531 Parcelable superState = super.onSaveInstanceState(); 532 return new SavedState(superState, getYear(), getMonth(), getDayOfMonth()); 533 } 534 535 @Override 536 protected void onRestoreInstanceState(Parcelable state) { 537 SavedState ss = (SavedState) state; 538 super.onRestoreInstanceState(ss.getSuperState()); 539 setDate(ss.mYear, ss.mMonth, ss.mDay); 540 updateSpinners(); 541 updateCalendarView(); 542 } 543 544 /** 545 * Initialize the state. If the provided values designate an inconsistent 546 * date the values are normalized before updating the spinners. 547 * 548 * @param year The initial year. 549 * @param monthOfYear The initial month <strong>starting from zero</strong>. 550 * @param dayOfMonth The initial day of the month. 551 * @param onDateChangedListener How user is notified date is changed by 552 * user, can be null. 553 */ 554 public void init(int year, int monthOfYear, int dayOfMonth, 555 OnDateChangedListener onDateChangedListener) { 556 setDate(year, monthOfYear, dayOfMonth); 557 updateSpinners(); 558 updateCalendarView(); 559 mOnDateChangedListener = onDateChangedListener; 560 } 561 562 /** 563 * Parses the given <code>date</code> and in case of success sets the result 564 * to the <code>outDate</code>. 565 * 566 * @return True if the date was parsed. 567 */ 568 private boolean parseDate(String date, Calendar outDate) { 569 try { 570 outDate.setTime(mDateFormat.parse(date)); 571 return true; 572 } catch (ParseException e) { 573 Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT); 574 return false; 575 } 576 } 577 578 private boolean isNewDate(int year, int month, int dayOfMonth) { 579 return (mCurrentDate.get(Calendar.YEAR) != year 580 || mCurrentDate.get(Calendar.MONTH) != dayOfMonth 581 || mCurrentDate.get(Calendar.DAY_OF_MONTH) != month); 582 } 583 584 private void setDate(int year, int month, int dayOfMonth) { 585 mCurrentDate.set(year, month, dayOfMonth); 586 if (mCurrentDate.before(mMinDate)) { 587 mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis()); 588 } else if (mCurrentDate.after(mMaxDate)) { 589 mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis()); 590 } 591 } 592 593 private void updateSpinners() { 594 // set the spinner ranges respecting the min and max dates 595 if (mCurrentDate.equals(mMinDate)) { 596 mDaySpinner.setMinValue(mCurrentDate.get(Calendar.DAY_OF_MONTH)); 597 mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH)); 598 mDaySpinner.setWrapSelectorWheel(false); 599 mMonthSpinner.setDisplayedValues(null); 600 mMonthSpinner.setMinValue(mCurrentDate.get(Calendar.MONTH)); 601 mMonthSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.MONTH)); 602 mMonthSpinner.setWrapSelectorWheel(false); 603 } else if (mCurrentDate.equals(mMaxDate)) { 604 mDaySpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.DAY_OF_MONTH)); 605 mDaySpinner.setMaxValue(mCurrentDate.get(Calendar.DAY_OF_MONTH)); 606 mDaySpinner.setWrapSelectorWheel(false); 607 mMonthSpinner.setDisplayedValues(null); 608 mMonthSpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.MONTH)); 609 mMonthSpinner.setMaxValue(mCurrentDate.get(Calendar.MONTH)); 610 mMonthSpinner.setWrapSelectorWheel(false); 611 } else { 612 mDaySpinner.setMinValue(1); 613 mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH)); 614 mDaySpinner.setWrapSelectorWheel(true); 615 mMonthSpinner.setDisplayedValues(null); 616 mMonthSpinner.setMinValue(0); 617 mMonthSpinner.setMaxValue(11); 618 mMonthSpinner.setWrapSelectorWheel(true); 619 } 620 621 // make sure the month names are a zero based array 622 // with the months in the month spinner 623 String[] displayedValues = Arrays.copyOfRange(mShortMonths, 624 mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1); 625 mMonthSpinner.setDisplayedValues(displayedValues); 626 627 // year spinner range does not change based on the current date 628 mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR)); 629 mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR)); 630 mYearSpinner.setWrapSelectorWheel(false); 631 632 // set the spinner values 633 mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR)); 634 mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH)); 635 mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH)); 636 } 637 638 /** 639 * Updates the calendar view with the current date. 640 */ 641 private void updateCalendarView() { 642 mCalendarView.setDate(mCurrentDate.getTimeInMillis(), false, false); 643 } 644 645 /** 646 * @return The selected year. 647 */ 648 public int getYear() { 649 return mCurrentDate.get(Calendar.YEAR); 650 } 651 652 /** 653 * @return The selected month. 654 */ 655 public int getMonth() { 656 return mCurrentDate.get(Calendar.MONTH); 657 } 658 659 /** 660 * @return The selected day of month. 661 */ 662 public int getDayOfMonth() { 663 return mCurrentDate.get(Calendar.DAY_OF_MONTH); 664 } 665 666 /** 667 * Notifies the listener, if such, for a change in the selected date. 668 */ 669 private void notifyDateChanged() { 670 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 671 if (mOnDateChangedListener != null) { 672 mOnDateChangedListener.onDateChanged(this, getYear(), getMonth(), getDayOfMonth()); 673 } 674 } 675 676 /** 677 * Sets the IME options for a spinner based on its ordering. 678 * 679 * @param spinner The spinner. 680 * @param spinnerCount The total spinner count. 681 * @param spinnerIndex The index of the given spinner. 682 */ 683 private void setImeOptions(NumberPicker spinner, int spinnerCount, int spinnerIndex) { 684 final int imeOptions; 685 if (spinnerIndex < spinnerCount - 1) { 686 imeOptions = EditorInfo.IME_ACTION_NEXT; 687 } else { 688 imeOptions = EditorInfo.IME_ACTION_DONE; 689 } 690 TextView input = (TextView) spinner.findViewById(R.id.numberpicker_input); 691 input.setImeOptions(imeOptions); 692 } 693 694 private void setContentDescriptions() { 695 // Day 696 String text = mContext.getString(R.string.date_picker_increment_day_button); 697 mDaySpinner.findViewById(R.id.increment).setContentDescription(text); 698 text = mContext.getString(R.string.date_picker_decrement_day_button); 699 mDaySpinner.findViewById(R.id.decrement).setContentDescription(text); 700 // Month 701 text = mContext.getString(R.string.date_picker_increment_month_button); 702 mMonthSpinner.findViewById(R.id.increment).setContentDescription(text); 703 text = mContext.getString(R.string.date_picker_decrement_month_button); 704 mMonthSpinner.findViewById(R.id.decrement).setContentDescription(text); 705 // Year 706 text = mContext.getString(R.string.date_picker_increment_year_button); 707 mYearSpinner.findViewById(R.id.increment).setContentDescription(text); 708 text = mContext.getString(R.string.date_picker_decrement_year_button); 709 mYearSpinner.findViewById(R.id.decrement).setContentDescription(text); 710 } 711 712 /** 713 * Class for managing state storing/restoring. 714 */ 715 private static class SavedState extends BaseSavedState { 716 717 private final int mYear; 718 719 private final int mMonth; 720 721 private final int mDay; 722 723 /** 724 * Constructor called from {@link DatePicker#onSaveInstanceState()} 725 */ 726 private SavedState(Parcelable superState, int year, int month, int day) { 727 super(superState); 728 mYear = year; 729 mMonth = month; 730 mDay = day; 731 } 732 733 /** 734 * Constructor called from {@link #CREATOR} 735 */ 736 private SavedState(Parcel in) { 737 super(in); 738 mYear = in.readInt(); 739 mMonth = in.readInt(); 740 mDay = in.readInt(); 741 } 742 743 @Override 744 public void writeToParcel(Parcel dest, int flags) { 745 super.writeToParcel(dest, flags); 746 dest.writeInt(mYear); 747 dest.writeInt(mMonth); 748 dest.writeInt(mDay); 749 } 750 751 @SuppressWarnings("all") 752 // suppress unused and hiding 753 public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() { 754 755 public SavedState createFromParcel(Parcel in) { 756 return new SavedState(in); 757 } 758 759 public SavedState[] newArray(int size) { 760 return new SavedState[size]; 761 } 762 }; 763 } 764} 765