| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.widget; |
| |
| import android.compat.annotation.UnsupportedAppUsage; |
| import android.content.Context; |
| import android.content.res.Configuration; |
| import android.content.res.TypedArray; |
| import android.icu.util.Calendar; |
| import android.os.Parcelable; |
| import android.text.InputType; |
| import android.text.TextUtils; |
| import android.text.format.DateFormat; |
| import android.util.AttributeSet; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.accessibility.AccessibilityEvent; |
| import android.view.inputmethod.EditorInfo; |
| import android.view.inputmethod.InputMethodManager; |
| import android.widget.DatePicker.AbstractDatePickerDelegate; |
| import android.widget.NumberPicker.OnValueChangeListener; |
| |
| import libcore.icu.ICU; |
| |
| import java.text.DateFormatSymbols; |
| import java.text.ParseException; |
| import java.text.SimpleDateFormat; |
| import java.util.Arrays; |
| import java.util.Locale; |
| |
| /** |
| * A delegate implementing the basic DatePicker |
| */ |
| class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate { |
| |
| private static final String DATE_FORMAT = "MM/dd/yyyy"; |
| |
| private static final int DEFAULT_START_YEAR = 1900; |
| |
| private static final int DEFAULT_END_YEAR = 2100; |
| |
| private static final boolean DEFAULT_CALENDAR_VIEW_SHOWN = true; |
| |
| private static final boolean DEFAULT_SPINNERS_SHOWN = true; |
| |
| private static final boolean DEFAULT_ENABLED_STATE = true; |
| |
| private final LinearLayout mSpinners; |
| |
| private final NumberPicker mDaySpinner; |
| |
| private final NumberPicker mMonthSpinner; |
| |
| private final NumberPicker mYearSpinner; |
| |
| private final EditText mDaySpinnerInput; |
| |
| private final EditText mMonthSpinnerInput; |
| |
| private final EditText mYearSpinnerInput; |
| |
| private final CalendarView mCalendarView; |
| |
| private String[] mShortMonths; |
| |
| private final java.text.DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT); |
| |
| private int mNumberOfMonths; |
| |
| private Calendar mTempDate; |
| |
| private Calendar mMinDate; |
| |
| private Calendar mMaxDate; |
| |
| private boolean mIsEnabled = DEFAULT_ENABLED_STATE; |
| |
| DatePickerSpinnerDelegate(DatePicker delegator, Context context, AttributeSet attrs, |
| int defStyleAttr, int defStyleRes) { |
| super(delegator, context); |
| |
| mDelegator = delegator; |
| mContext = context; |
| |
| // initialization based on locale |
| setCurrentLocale(Locale.getDefault()); |
| |
| final TypedArray attributesArray = context.obtainStyledAttributes(attrs, |
| com.android.internal.R.styleable.DatePicker, defStyleAttr, defStyleRes); |
| boolean spinnersShown = attributesArray.getBoolean(com.android.internal.R.styleable.DatePicker_spinnersShown, |
| DEFAULT_SPINNERS_SHOWN); |
| boolean calendarViewShown = attributesArray.getBoolean( |
| com.android.internal.R.styleable.DatePicker_calendarViewShown, DEFAULT_CALENDAR_VIEW_SHOWN); |
| int startYear = attributesArray.getInt(com.android.internal.R.styleable.DatePicker_startYear, |
| DEFAULT_START_YEAR); |
| int endYear = attributesArray.getInt(com.android.internal.R.styleable.DatePicker_endYear, DEFAULT_END_YEAR); |
| String minDate = attributesArray.getString(com.android.internal.R.styleable.DatePicker_minDate); |
| String maxDate = attributesArray.getString(com.android.internal.R.styleable.DatePicker_maxDate); |
| int layoutResourceId = attributesArray.getResourceId( |
| com.android.internal.R.styleable.DatePicker_legacyLayout, com.android.internal.R.layout.date_picker_legacy); |
| attributesArray.recycle(); |
| |
| LayoutInflater inflater = (LayoutInflater) context |
| .getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
| final View view = inflater.inflate(layoutResourceId, mDelegator, true); |
| view.setSaveFromParentEnabled(false); |
| |
| OnValueChangeListener onChangeListener = new OnValueChangeListener() { |
| public void onValueChange(NumberPicker picker, int oldVal, int newVal) { |
| updateInputState(); |
| mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis()); |
| // take care of wrapping of days and months to update greater fields |
| if (picker == mDaySpinner) { |
| int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH); |
| if (oldVal == maxDayOfMonth && newVal == 1) { |
| mTempDate.add(Calendar.DAY_OF_MONTH, 1); |
| } else if (oldVal == 1 && newVal == maxDayOfMonth) { |
| mTempDate.add(Calendar.DAY_OF_MONTH, -1); |
| } else { |
| mTempDate.add(Calendar.DAY_OF_MONTH, newVal - oldVal); |
| } |
| } else if (picker == mMonthSpinner) { |
| if (oldVal == 11 && newVal == 0) { |
| mTempDate.add(Calendar.MONTH, 1); |
| } else if (oldVal == 0 && newVal == 11) { |
| mTempDate.add(Calendar.MONTH, -1); |
| } else { |
| mTempDate.add(Calendar.MONTH, newVal - oldVal); |
| } |
| } else if (picker == mYearSpinner) { |
| mTempDate.set(Calendar.YEAR, newVal); |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| // now set the date to the adjusted one |
| setDate(mTempDate.get(Calendar.YEAR), mTempDate.get(Calendar.MONTH), |
| mTempDate.get(Calendar.DAY_OF_MONTH)); |
| updateSpinners(); |
| updateCalendarView(); |
| notifyDateChanged(); |
| } |
| }; |
| |
| mSpinners = (LinearLayout) mDelegator.findViewById(com.android.internal.R.id.pickers); |
| |
| // calendar view day-picker |
| mCalendarView = (CalendarView) mDelegator.findViewById(com.android.internal.R.id.calendar_view); |
| mCalendarView.setOnDateChangeListener(new CalendarView.OnDateChangeListener() { |
| public void onSelectedDayChange(CalendarView view, int year, int month, int monthDay) { |
| setDate(year, month, monthDay); |
| updateSpinners(); |
| notifyDateChanged(); |
| } |
| }); |
| |
| // day |
| mDaySpinner = (NumberPicker) mDelegator.findViewById(com.android.internal.R.id.day); |
| mDaySpinner.setFormatter(NumberPicker.getTwoDigitFormatter()); |
| mDaySpinner.setOnLongPressUpdateInterval(100); |
| mDaySpinner.setOnValueChangedListener(onChangeListener); |
| mDaySpinnerInput = (EditText) mDaySpinner.findViewById(com.android.internal.R.id.numberpicker_input); |
| |
| // month |
| mMonthSpinner = (NumberPicker) mDelegator.findViewById(com.android.internal.R.id.month); |
| mMonthSpinner.setMinValue(0); |
| mMonthSpinner.setMaxValue(mNumberOfMonths - 1); |
| mMonthSpinner.setDisplayedValues(mShortMonths); |
| mMonthSpinner.setOnLongPressUpdateInterval(200); |
| mMonthSpinner.setOnValueChangedListener(onChangeListener); |
| mMonthSpinnerInput = (EditText) mMonthSpinner.findViewById(com.android.internal.R.id.numberpicker_input); |
| |
| // year |
| mYearSpinner = (NumberPicker) mDelegator.findViewById(com.android.internal.R.id.year); |
| mYearSpinner.setOnLongPressUpdateInterval(100); |
| mYearSpinner.setOnValueChangedListener(onChangeListener); |
| mYearSpinnerInput = (EditText) mYearSpinner.findViewById(com.android.internal.R.id.numberpicker_input); |
| |
| // show only what the user required but make sure we |
| // show something and the spinners have higher priority |
| if (!spinnersShown && !calendarViewShown) { |
| setSpinnersShown(true); |
| } else { |
| setSpinnersShown(spinnersShown); |
| setCalendarViewShown(calendarViewShown); |
| } |
| |
| // set the min date giving priority of the minDate over startYear |
| mTempDate.clear(); |
| if (!TextUtils.isEmpty(minDate)) { |
| if (!parseDate(minDate, mTempDate)) { |
| mTempDate.set(startYear, 0, 1); |
| } |
| } else { |
| mTempDate.set(startYear, 0, 1); |
| } |
| setMinDate(mTempDate.getTimeInMillis()); |
| |
| // set the max date giving priority of the maxDate over endYear |
| mTempDate.clear(); |
| if (!TextUtils.isEmpty(maxDate)) { |
| if (!parseDate(maxDate, mTempDate)) { |
| mTempDate.set(endYear, 11, 31); |
| } |
| } else { |
| mTempDate.set(endYear, 11, 31); |
| } |
| setMaxDate(mTempDate.getTimeInMillis()); |
| |
| // initialize to current date |
| mCurrentDate.setTimeInMillis(System.currentTimeMillis()); |
| init(mCurrentDate.get(Calendar.YEAR), mCurrentDate.get(Calendar.MONTH), mCurrentDate |
| .get(Calendar.DAY_OF_MONTH), null); |
| |
| // re-order the number spinners to match the current date format |
| reorderSpinners(); |
| |
| // accessibility |
| setContentDescriptions(); |
| |
| // If not explicitly specified this view is important for accessibility. |
| if (mDelegator.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { |
| mDelegator.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); |
| } |
| } |
| |
| @Override |
| public void init(int year, int monthOfYear, int dayOfMonth, |
| DatePicker.OnDateChangedListener onDateChangedListener) { |
| setDate(year, monthOfYear, dayOfMonth); |
| updateSpinners(); |
| updateCalendarView(); |
| |
| mOnDateChangedListener = onDateChangedListener; |
| } |
| |
| @Override |
| public void updateDate(int year, int month, int dayOfMonth) { |
| if (!isNewDate(year, month, dayOfMonth)) { |
| return; |
| } |
| setDate(year, month, dayOfMonth); |
| updateSpinners(); |
| updateCalendarView(); |
| notifyDateChanged(); |
| } |
| |
| @Override |
| public int getYear() { |
| return mCurrentDate.get(Calendar.YEAR); |
| } |
| |
| @Override |
| public int getMonth() { |
| return mCurrentDate.get(Calendar.MONTH); |
| } |
| |
| @Override |
| public int getDayOfMonth() { |
| return mCurrentDate.get(Calendar.DAY_OF_MONTH); |
| } |
| |
| @Override |
| public void setFirstDayOfWeek(int firstDayOfWeek) { |
| mCalendarView.setFirstDayOfWeek(firstDayOfWeek); |
| } |
| |
| @Override |
| public int getFirstDayOfWeek() { |
| return mCalendarView.getFirstDayOfWeek(); |
| } |
| |
| @Override |
| public void setMinDate(long minDate) { |
| mTempDate.setTimeInMillis(minDate); |
| if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR) |
| && mTempDate.get(Calendar.DAY_OF_YEAR) == mMinDate.get(Calendar.DAY_OF_YEAR)) { |
| // Same day, no-op. |
| return; |
| } |
| mMinDate.setTimeInMillis(minDate); |
| mCalendarView.setMinDate(minDate); |
| if (mCurrentDate.before(mMinDate)) { |
| mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis()); |
| updateCalendarView(); |
| } |
| updateSpinners(); |
| } |
| |
| @Override |
| public Calendar getMinDate() { |
| final Calendar minDate = Calendar.getInstance(); |
| minDate.setTimeInMillis(mCalendarView.getMinDate()); |
| return minDate; |
| } |
| |
| @Override |
| public void setMaxDate(long maxDate) { |
| mTempDate.setTimeInMillis(maxDate); |
| if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR) |
| && mTempDate.get(Calendar.DAY_OF_YEAR) == mMaxDate.get(Calendar.DAY_OF_YEAR)) { |
| // Same day, no-op. |
| return; |
| } |
| mMaxDate.setTimeInMillis(maxDate); |
| mCalendarView.setMaxDate(maxDate); |
| if (mCurrentDate.after(mMaxDate)) { |
| mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis()); |
| updateCalendarView(); |
| } |
| updateSpinners(); |
| } |
| |
| @Override |
| public Calendar getMaxDate() { |
| final Calendar maxDate = Calendar.getInstance(); |
| maxDate.setTimeInMillis(mCalendarView.getMaxDate()); |
| return maxDate; |
| } |
| |
| @Override |
| public void setEnabled(boolean enabled) { |
| mDaySpinner.setEnabled(enabled); |
| mMonthSpinner.setEnabled(enabled); |
| mYearSpinner.setEnabled(enabled); |
| mCalendarView.setEnabled(enabled); |
| mIsEnabled = enabled; |
| } |
| |
| @Override |
| public boolean isEnabled() { |
| return mIsEnabled; |
| } |
| |
| @Override |
| public CalendarView getCalendarView() { |
| return mCalendarView; |
| } |
| |
| @Override |
| public void setCalendarViewShown(boolean shown) { |
| mCalendarView.setVisibility(shown ? View.VISIBLE : View.GONE); |
| } |
| |
| @Override |
| public boolean getCalendarViewShown() { |
| return (mCalendarView.getVisibility() == View.VISIBLE); |
| } |
| |
| @Override |
| public void setSpinnersShown(boolean shown) { |
| mSpinners.setVisibility(shown ? View.VISIBLE : View.GONE); |
| } |
| |
| @Override |
| public boolean getSpinnersShown() { |
| return mSpinners.isShown(); |
| } |
| |
| @Override |
| public void onConfigurationChanged(Configuration newConfig) { |
| setCurrentLocale(newConfig.locale); |
| } |
| |
| @Override |
| public Parcelable onSaveInstanceState(Parcelable superState) { |
| return new SavedState(superState, getYear(), getMonth(), getDayOfMonth(), |
| getMinDate().getTimeInMillis(), getMaxDate().getTimeInMillis()); |
| } |
| |
| @Override |
| public void onRestoreInstanceState(Parcelable state) { |
| if (state instanceof SavedState) { |
| final SavedState ss = (SavedState) state; |
| setDate(ss.getSelectedYear(), ss.getSelectedMonth(), ss.getSelectedDay()); |
| updateSpinners(); |
| updateCalendarView(); |
| } |
| } |
| |
| @Override |
| public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { |
| onPopulateAccessibilityEvent(event); |
| return true; |
| } |
| |
| /** |
| * Sets the current locale. |
| * |
| * @param locale The current locale. |
| */ |
| @Override |
| protected void setCurrentLocale(Locale locale) { |
| super.setCurrentLocale(locale); |
| |
| mTempDate = getCalendarForLocale(mTempDate, locale); |
| mMinDate = getCalendarForLocale(mMinDate, locale); |
| mMaxDate = getCalendarForLocale(mMaxDate, locale); |
| mCurrentDate = getCalendarForLocale(mCurrentDate, locale); |
| |
| mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1; |
| mShortMonths = new DateFormatSymbols().getShortMonths(); |
| |
| if (usingNumericMonths()) { |
| // We're in a locale where a date should either be all-numeric, or all-text. |
| // All-text would require custom NumberPicker formatters for day and year. |
| mShortMonths = new String[mNumberOfMonths]; |
| for (int i = 0; i < mNumberOfMonths; ++i) { |
| mShortMonths[i] = String.format("%d", i + 1); |
| } |
| } |
| } |
| |
| /** |
| * Tests whether the current locale is one where there are no real month names, |
| * such as Chinese, Japanese, or Korean locales. |
| */ |
| private boolean usingNumericMonths() { |
| return Character.isDigit(mShortMonths[Calendar.JANUARY].charAt(0)); |
| } |
| |
| /** |
| * Gets a calendar for locale bootstrapped with the value of a given calendar. |
| * |
| * @param oldCalendar The old calendar. |
| * @param locale The locale. |
| */ |
| private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) { |
| if (oldCalendar == null) { |
| return Calendar.getInstance(locale); |
| } else { |
| final long currentTimeMillis = oldCalendar.getTimeInMillis(); |
| Calendar newCalendar = Calendar.getInstance(locale); |
| newCalendar.setTimeInMillis(currentTimeMillis); |
| return newCalendar; |
| } |
| } |
| |
| /** |
| * Reorders the spinners according to the date format that is |
| * explicitly set by the user and if no such is set fall back |
| * to the current locale's default format. |
| */ |
| private void reorderSpinners() { |
| mSpinners.removeAllViews(); |
| // We use numeric spinners for year and day, but textual months. Ask icu4c what |
| // order the user's locale uses for that combination. http://b/7207103. |
| String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), "yyyyMMMdd"); |
| char[] order = ICU.getDateFormatOrder(pattern); |
| final int spinnerCount = order.length; |
| for (int i = 0; i < spinnerCount; i++) { |
| switch (order[i]) { |
| case 'd': |
| mSpinners.addView(mDaySpinner); |
| setImeOptions(mDaySpinner, spinnerCount, i); |
| break; |
| case 'M': |
| mSpinners.addView(mMonthSpinner); |
| setImeOptions(mMonthSpinner, spinnerCount, i); |
| break; |
| case 'y': |
| mSpinners.addView(mYearSpinner); |
| setImeOptions(mYearSpinner, spinnerCount, i); |
| break; |
| default: |
| throw new IllegalArgumentException(Arrays.toString(order)); |
| } |
| } |
| } |
| |
| /** |
| * Parses the given <code>date</code> and in case of success sets the result |
| * to the <code>outDate</code>. |
| * |
| * @return True if the date was parsed. |
| */ |
| private boolean parseDate(String date, Calendar outDate) { |
| try { |
| outDate.setTime(mDateFormat.parse(date)); |
| return true; |
| } catch (ParseException e) { |
| e.printStackTrace(); |
| return false; |
| } |
| } |
| |
| private boolean isNewDate(int year, int month, int dayOfMonth) { |
| return (mCurrentDate.get(Calendar.YEAR) != year |
| || mCurrentDate.get(Calendar.MONTH) != month |
| || mCurrentDate.get(Calendar.DAY_OF_MONTH) != dayOfMonth); |
| } |
| |
| @UnsupportedAppUsage |
| private void setDate(int year, int month, int dayOfMonth) { |
| mCurrentDate.set(year, month, dayOfMonth); |
| resetAutofilledValue(); |
| if (mCurrentDate.before(mMinDate)) { |
| mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis()); |
| } else if (mCurrentDate.after(mMaxDate)) { |
| mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis()); |
| } |
| } |
| |
| @UnsupportedAppUsage |
| private void updateSpinners() { |
| // set the spinner ranges respecting the min and max dates |
| if (mCurrentDate.equals(mMinDate)) { |
| mDaySpinner.setMinValue(mCurrentDate.get(Calendar.DAY_OF_MONTH)); |
| mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH)); |
| mDaySpinner.setWrapSelectorWheel(false); |
| mMonthSpinner.setDisplayedValues(null); |
| mMonthSpinner.setMinValue(mCurrentDate.get(Calendar.MONTH)); |
| mMonthSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.MONTH)); |
| mMonthSpinner.setWrapSelectorWheel(false); |
| } else if (mCurrentDate.equals(mMaxDate)) { |
| mDaySpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.DAY_OF_MONTH)); |
| mDaySpinner.setMaxValue(mCurrentDate.get(Calendar.DAY_OF_MONTH)); |
| mDaySpinner.setWrapSelectorWheel(false); |
| mMonthSpinner.setDisplayedValues(null); |
| mMonthSpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.MONTH)); |
| mMonthSpinner.setMaxValue(mCurrentDate.get(Calendar.MONTH)); |
| mMonthSpinner.setWrapSelectorWheel(false); |
| } else { |
| mDaySpinner.setMinValue(1); |
| mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH)); |
| mDaySpinner.setWrapSelectorWheel(true); |
| mMonthSpinner.setDisplayedValues(null); |
| mMonthSpinner.setMinValue(0); |
| mMonthSpinner.setMaxValue(11); |
| mMonthSpinner.setWrapSelectorWheel(true); |
| } |
| |
| // make sure the month names are a zero based array |
| // with the months in the month spinner |
| String[] displayedValues = Arrays.copyOfRange(mShortMonths, |
| mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1); |
| mMonthSpinner.setDisplayedValues(displayedValues); |
| |
| // year spinner range does not change based on the current date |
| mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR)); |
| mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR)); |
| mYearSpinner.setWrapSelectorWheel(false); |
| |
| // set the spinner values |
| mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR)); |
| mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH)); |
| mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH)); |
| |
| if (usingNumericMonths()) { |
| mMonthSpinnerInput.setRawInputType(InputType.TYPE_CLASS_NUMBER); |
| } |
| } |
| |
| /** |
| * Updates the calendar view with the current date. |
| */ |
| @UnsupportedAppUsage |
| private void updateCalendarView() { |
| mCalendarView.setDate(mCurrentDate.getTimeInMillis(), false, false); |
| } |
| |
| |
| /** |
| * Notifies the listener, if such, for a change in the selected date. |
| */ |
| @UnsupportedAppUsage |
| private void notifyDateChanged() { |
| mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); |
| if (mOnDateChangedListener != null) { |
| mOnDateChangedListener.onDateChanged(mDelegator, getYear(), getMonth(), |
| getDayOfMonth()); |
| } |
| if (mAutoFillChangeListener != null) { |
| mAutoFillChangeListener.onDateChanged(mDelegator, getYear(), getMonth(), |
| getDayOfMonth()); |
| } |
| } |
| |
| /** |
| * Sets the IME options for a spinner based on its ordering. |
| * |
| * @param spinner The spinner. |
| * @param spinnerCount The total spinner count. |
| * @param spinnerIndex The index of the given spinner. |
| */ |
| private void setImeOptions(NumberPicker spinner, int spinnerCount, int spinnerIndex) { |
| final int imeOptions; |
| if (spinnerIndex < spinnerCount - 1) { |
| imeOptions = EditorInfo.IME_ACTION_NEXT; |
| } else { |
| imeOptions = EditorInfo.IME_ACTION_DONE; |
| } |
| TextView input = (TextView) spinner.findViewById(com.android.internal.R.id.numberpicker_input); |
| input.setImeOptions(imeOptions); |
| } |
| |
| private void setContentDescriptions() { |
| // Day |
| trySetContentDescription(mDaySpinner, com.android.internal.R.id.increment, |
| com.android.internal.R.string.date_picker_increment_day_button); |
| trySetContentDescription(mDaySpinner, com.android.internal.R.id.decrement, |
| com.android.internal.R.string.date_picker_decrement_day_button); |
| // Month |
| trySetContentDescription(mMonthSpinner, com.android.internal.R.id.increment, |
| com.android.internal.R.string.date_picker_increment_month_button); |
| trySetContentDescription(mMonthSpinner, com.android.internal.R.id.decrement, |
| com.android.internal.R.string.date_picker_decrement_month_button); |
| // Year |
| trySetContentDescription(mYearSpinner, com.android.internal.R.id.increment, |
| com.android.internal.R.string.date_picker_increment_year_button); |
| trySetContentDescription(mYearSpinner, com.android.internal.R.id.decrement, |
| com.android.internal.R.string.date_picker_decrement_year_button); |
| } |
| |
| private void trySetContentDescription(View root, int viewId, int contDescResId) { |
| View target = root.findViewById(viewId); |
| if (target != null) { |
| target.setContentDescription(mContext.getString(contDescResId)); |
| } |
| } |
| |
| @UnsupportedAppUsage |
| private void updateInputState() { |
| // Make sure that if the user changes the value and the IME is active |
| // for one of the inputs if this widget, the IME is closed. If the user |
| // changed the value via the IME and there is a next input the IME will |
| // be shown, otherwise the user chose another means of changing the |
| // value and having the IME up makes no sense. |
| InputMethodManager inputMethodManager = mContext.getSystemService(InputMethodManager.class); |
| if (inputMethodManager != null) { |
| if (inputMethodManager.isActive(mYearSpinnerInput)) { |
| mYearSpinnerInput.clearFocus(); |
| inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0); |
| } else if (inputMethodManager.isActive(mMonthSpinnerInput)) { |
| mMonthSpinnerInput.clearFocus(); |
| inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0); |
| } else if (inputMethodManager.isActive(mDaySpinnerInput)) { |
| mDaySpinnerInput.clearFocus(); |
| inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0); |
| } |
| } |
| } |
| } |