diff options
author | Fabrice Di Meglio <fdimeglio@google.com> | 2013-08-19 13:16:46 -0700 |
---|---|---|
committer | Fabrice Di Meglio <fdimeglio@google.com> | 2013-08-21 18:47:04 -0700 |
commit | 9e4009ea150a7020fb8cf315281679979e67e762 (patch) | |
tree | 0ef86dd7c4db111079569d51d7825281d85e1309 /core/java/android/widget/TimePicker.java | |
parent | c63d85a051008ae33b5417925d217bc47bddf6d5 (diff) | |
download | frameworks_base-9e4009ea150a7020fb8cf315281679979e67e762.zip frameworks_base-9e4009ea150a7020fb8cf315281679979e67e762.tar.gz frameworks_base-9e4009ea150a7020fb8cf315281679979e67e762.tar.bz2 |
Decouple TimePicker code
- introduce a TimePickerDelegate interface to be able to have several
TimePicker implementations
- code refactoring
Change-Id: I0d8bdfdb4c2723a51311c01fbd485e34983bb423
Diffstat (limited to 'core/java/android/widget/TimePicker.java')
-rw-r--r-- | core/java/android/widget/TimePicker.java | 1159 |
1 files changed, 648 insertions, 511 deletions
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index 1c1d77a..cc61c36 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -57,636 +57,773 @@ import java.util.Locale; @Widget public class TimePicker extends FrameLayout { - private static final boolean DEFAULT_ENABLED_STATE = true; + private TimePickerDelegate mDelegate; - private static final int HOURS_IN_HALF_DAY = 12; + /** + * The callback interface used to indicate the time has been adjusted. + */ + public interface OnTimeChangedListener { + + /** + * @param view The view associated with this listener. + * @param hourOfDay The current hour. + * @param minute The current minute. + */ + void onTimeChanged(TimePicker view, int hourOfDay, int minute); + } + + public TimePicker(Context context) { + this(context, null); + } + + public TimePicker(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.timePickerStyle); + } + + public TimePicker(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + mDelegate = new LegacyTimePickerDelegate(this, context, attrs, defStyle); + } + + /** + * Set the current hour. + */ + public void setCurrentHour(Integer currentHour) { + mDelegate.setCurrentHour(currentHour); + } + + /** + * @return The current hour in the range (0-23). + */ + public Integer getCurrentHour() { + return mDelegate.getCurrentHour(); + } + + /** + * Set the current minute (0-59). + */ + public void setCurrentMinute(Integer currentMinute) { + mDelegate.setCurrentMinute(currentMinute); + } + + /** + * @return The current minute. + */ + public Integer getCurrentMinute() { + return mDelegate.getCurrentMinute(); + } + + /** + * Set whether in 24 hour or AM/PM mode. + * + * @param is24HourView True = 24 hour mode. False = AM/PM. + */ + public void setIs24HourView(Boolean is24HourView) { + mDelegate.setIs24HourView(is24HourView); + } + + /** + * @return true if this is in 24 hour view else false. + */ + public boolean is24HourView() { + return mDelegate.is24HourView(); + } /** - * A no-op callback used in the constructor to avoid null checks later in - * the code. + * Set the callback that indicates the time has been adjusted by the user. + * + * @param onTimeChangedListener the callback, should not be null. */ - private static final OnTimeChangedListener NO_OP_CHANGE_LISTENER = new OnTimeChangedListener() { - public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { + public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) { + mDelegate.setOnTimeChangedListener(onTimeChangedListener); + } + + @Override + public void setEnabled(boolean enabled) { + if (mDelegate.isEnabled() == enabled) { + return; } - }; + super.setEnabled(enabled); + mDelegate.setEnabled(enabled); + } - // state - private boolean mIs24HourView; + @Override + public boolean isEnabled() { + return mDelegate.isEnabled(); + } - private boolean mIsAm; + @Override + public int getBaseline() { + return mDelegate.getBaseline(); + } - // ui components - private final NumberPicker mHourSpinner; + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + mDelegate.onConfigurationChanged(newConfig); + } - private final NumberPicker mMinuteSpinner; + @Override + protected Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + return mDelegate.onSaveInstanceState(superState); + } - private final NumberPicker mAmPmSpinner; + @Override + protected void onRestoreInstanceState(Parcelable state) { + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + mDelegate.onRestoreInstanceState(ss); + } - private final EditText mHourSpinnerInput; + @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + return mDelegate.dispatchPopulateAccessibilityEvent(event); + } - private final EditText mMinuteSpinnerInput; + @Override + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + super.onPopulateAccessibilityEvent(event); + mDelegate.onPopulateAccessibilityEvent(event); + } - private final EditText mAmPmSpinnerInput; + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + mDelegate.onInitializeAccessibilityEvent(event); + } - private final TextView mDivider; + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + mDelegate.onInitializeAccessibilityNodeInfo(info); + } + + /** + * A delegate interface that defined the public API of the TimePicker. Allows different + * TimePicker implementations. This would need to be implemented by the TimePicker delegates + * for the real behavior. + */ + private interface TimePickerDelegate { + void setCurrentHour(Integer currentHour); + Integer getCurrentHour(); - // Note that the legacy implementation of the TimePicker is - // using a button for toggling between AM/PM while the new - // version uses a NumberPicker spinner. Therefore the code - // accommodates these two cases to be backwards compatible. - private final Button mAmPmButton; + void setCurrentMinute(Integer currentMinute); + Integer getCurrentMinute(); - private final String[] mAmPmStrings; + void setIs24HourView(Boolean is24HourView); + boolean is24HourView(); - private boolean mIsEnabled = DEFAULT_ENABLED_STATE; + void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener); - // callbacks - private OnTimeChangedListener mOnTimeChangedListener; + void setEnabled(boolean enabled); + boolean isEnabled(); - private Calendar mTempCalendar; + int getBaseline(); - private Locale mCurrentLocale; + void onConfigurationChanged(Configuration newConfig); - private boolean mHourWithTwoDigit; - private char mHourFormat; + Parcelable onSaveInstanceState(Parcelable superState); + void onRestoreInstanceState(Parcelable state); + + boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event); + void onPopulateAccessibilityEvent(AccessibilityEvent event); + void onInitializeAccessibilityEvent(AccessibilityEvent event); + void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info); + } /** - * The callback interface used to indicate the time has been adjusted. + * A delegate implementing the basic TimePicker */ - public interface OnTimeChangedListener { + private static class LegacyTimePickerDelegate implements TimePickerDelegate { + // the delegator + private TimePicker mDelegator; + + private static final boolean DEFAULT_ENABLED_STATE = true; + + private static final int HOURS_IN_HALF_DAY = 12; + + // state + private boolean mIs24HourView; + + private boolean mIsAm; + + // ui components + private final NumberPicker mHourSpinner; + + private final NumberPicker mMinuteSpinner; + + private final NumberPicker mAmPmSpinner; + + private final EditText mHourSpinnerInput; + + private final EditText mMinuteSpinnerInput; + + private final EditText mAmPmSpinnerInput; + + private final TextView mDivider; + + // Note that the legacy implementation of the TimePicker is + // using a button for toggling between AM/PM while the new + // version uses a NumberPicker spinner. Therefore the code + // accommodates these two cases to be backwards compatible. + private final Button mAmPmButton; + + private final String[] mAmPmStrings; + + private boolean mIsEnabled = DEFAULT_ENABLED_STATE; + + // callbacks + private OnTimeChangedListener mOnTimeChangedListener; + + private Calendar mTempCalendar; + + private Locale mCurrentLocale; + + private boolean mHourWithTwoDigit; + private char mHourFormat; /** - * @param view The view associated with this listener. - * @param hourOfDay The current hour. - * @param minute The current minute. + * A no-op callback used in the constructor to avoid null checks later in + * the code. */ - void onTimeChanged(TimePicker view, int hourOfDay, int minute); - } + private static final OnTimeChangedListener NO_OP_CHANGE_LISTENER = + new OnTimeChangedListener() { + public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { + } + }; - public TimePicker(Context context) { - this(context, null); - } + public LegacyTimePickerDelegate(TimePicker delegator, Context context, AttributeSet attrs, + int defStyle) { + mDelegator = delegator; - public TimePicker(Context context, AttributeSet attrs) { - this(context, attrs, R.attr.timePickerStyle); - } + // initialization based on locale + setCurrentLocale(Locale.getDefault()); - public TimePicker(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); + // process style attributes + TypedArray attributesArray = context.obtainStyledAttributes( + attrs, R.styleable.TimePicker, defStyle, 0); + int layoutResourceId = attributesArray.getResourceId( + R.styleable.TimePicker_internalLayout, R.layout.time_picker); + attributesArray.recycle(); - // initialization based on locale - setCurrentLocale(Locale.getDefault()); - - // process style attributes - TypedArray attributesArray = context.obtainStyledAttributes( - attrs, R.styleable.TimePicker, defStyle, 0); - int layoutResourceId = attributesArray.getResourceId( - R.styleable.TimePicker_internalLayout, R.layout.time_picker); - attributesArray.recycle(); - - LayoutInflater inflater = (LayoutInflater) context.getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate(layoutResourceId, this, true); - - // hour - mHourSpinner = (NumberPicker) findViewById(R.id.hour); - mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { - public void onValueChange(NumberPicker spinner, int oldVal, int newVal) { - updateInputState(); - if (!is24HourView()) { - if ((oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) - || (oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1)) { - mIsAm = !mIsAm; - updateAmPmControl(); + LayoutInflater inflater = (LayoutInflater) context.getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + inflater.inflate(layoutResourceId, mDelegator, true); + + // hour + mHourSpinner = (NumberPicker) delegator.findViewById(R.id.hour); + mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { + public void onValueChange(NumberPicker spinner, int oldVal, int newVal) { + updateInputState(); + if (!is24HourView()) { + if ((oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) || + (oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1)) { + mIsAm = !mIsAm; + updateAmPmControl(); + } } + onTimeChanged(); } - onTimeChanged(); + }); + mHourSpinnerInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input); + mHourSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT); + + // divider (only for the new widget style) + mDivider = (TextView) mDelegator.findViewById(R.id.divider); + if (mDivider != null) { + setDividerText(); } - }); - mHourSpinnerInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input); - mHourSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT); - - // divider (only for the new widget style) - mDivider = (TextView) findViewById(R.id.divider); - if (mDivider != null) { - setDividerText(); - } - - // minute - mMinuteSpinner = (NumberPicker) findViewById(R.id.minute); - mMinuteSpinner.setMinValue(0); - mMinuteSpinner.setMaxValue(59); - mMinuteSpinner.setOnLongPressUpdateInterval(100); - mMinuteSpinner.setFormatter(NumberPicker.getTwoDigitFormatter()); - mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { - public void onValueChange(NumberPicker spinner, int oldVal, int newVal) { - updateInputState(); - int minValue = mMinuteSpinner.getMinValue(); - int maxValue = mMinuteSpinner.getMaxValue(); - if (oldVal == maxValue && newVal == minValue) { - int newHour = mHourSpinner.getValue() + 1; - if (!is24HourView() && newHour == HOURS_IN_HALF_DAY) { + + // minute + mMinuteSpinner = (NumberPicker) mDelegator.findViewById(R.id.minute); + mMinuteSpinner.setMinValue(0); + mMinuteSpinner.setMaxValue(59); + mMinuteSpinner.setOnLongPressUpdateInterval(100); + mMinuteSpinner.setFormatter(NumberPicker.getTwoDigitFormatter()); + mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { + public void onValueChange(NumberPicker spinner, int oldVal, int newVal) { + updateInputState(); + int minValue = mMinuteSpinner.getMinValue(); + int maxValue = mMinuteSpinner.getMaxValue(); + if (oldVal == maxValue && newVal == minValue) { + int newHour = mHourSpinner.getValue() + 1; + if (!is24HourView() && newHour == HOURS_IN_HALF_DAY) { + mIsAm = !mIsAm; + updateAmPmControl(); + } + mHourSpinner.setValue(newHour); + } else if (oldVal == minValue && newVal == maxValue) { + int newHour = mHourSpinner.getValue() - 1; + if (!is24HourView() && newHour == HOURS_IN_HALF_DAY - 1) { + mIsAm = !mIsAm; + updateAmPmControl(); + } + mHourSpinner.setValue(newHour); + } + onTimeChanged(); + } + }); + mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input); + mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT); + + /* Get the localized am/pm strings and use them in the spinner */ + mAmPmStrings = new DateFormatSymbols().getAmPmStrings(); + + // am/pm + View amPmView = mDelegator.findViewById(R.id.amPm); + if (amPmView instanceof Button) { + mAmPmSpinner = null; + mAmPmSpinnerInput = null; + mAmPmButton = (Button) amPmView; + mAmPmButton.setOnClickListener(new OnClickListener() { + public void onClick(View button) { + button.requestFocus(); mIsAm = !mIsAm; updateAmPmControl(); + onTimeChanged(); } - mHourSpinner.setValue(newHour); - } else if (oldVal == minValue && newVal == maxValue) { - int newHour = mHourSpinner.getValue() - 1; - if (!is24HourView() && newHour == HOURS_IN_HALF_DAY - 1) { + }); + } else { + mAmPmButton = null; + mAmPmSpinner = (NumberPicker) amPmView; + mAmPmSpinner.setMinValue(0); + mAmPmSpinner.setMaxValue(1); + mAmPmSpinner.setDisplayedValues(mAmPmStrings); + mAmPmSpinner.setOnValueChangedListener(new OnValueChangeListener() { + public void onValueChange(NumberPicker picker, int oldVal, int newVal) { + updateInputState(); + picker.requestFocus(); mIsAm = !mIsAm; updateAmPmControl(); + onTimeChanged(); } - mHourSpinner.setValue(newHour); - } - onTimeChanged(); + }); + mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input); + mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE); } - }); - mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input); - mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT); - - /* Get the localized am/pm strings and use them in the spinner */ - mAmPmStrings = new DateFormatSymbols().getAmPmStrings(); - - // am/pm - View amPmView = findViewById(R.id.amPm); - if (amPmView instanceof Button) { - mAmPmSpinner = null; - mAmPmSpinnerInput = null; - mAmPmButton = (Button) amPmView; - mAmPmButton.setOnClickListener(new OnClickListener() { - public void onClick(View button) { - button.requestFocus(); - mIsAm = !mIsAm; - updateAmPmControl(); - onTimeChanged(); - } - }); - } else { - mAmPmButton = null; - mAmPmSpinner = (NumberPicker) amPmView; - mAmPmSpinner.setMinValue(0); - mAmPmSpinner.setMaxValue(1); - mAmPmSpinner.setDisplayedValues(mAmPmStrings); - mAmPmSpinner.setOnValueChangedListener(new OnValueChangeListener() { - public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - updateInputState(); - picker.requestFocus(); - mIsAm = !mIsAm; - updateAmPmControl(); - onTimeChanged(); + + if (isAmPmAtStart()) { + // Move the am/pm view to the beginning + ViewGroup amPmParent = (ViewGroup) delegator.findViewById(R.id.timePickerLayout); + amPmParent.removeView(amPmView); + amPmParent.addView(amPmView, 0); + // Swap layout margins if needed. They may be not symmetrical (Old Standard Theme + // for example and not for Holo Theme) + ViewGroup.MarginLayoutParams lp = + (ViewGroup.MarginLayoutParams) amPmView.getLayoutParams(); + final int startMargin = lp.getMarginStart(); + final int endMargin = lp.getMarginEnd(); + if (startMargin != endMargin) { + lp.setMarginStart(endMargin); + lp.setMarginEnd(startMargin); } - }); - mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input); - mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE); - } - - if (isAmPmAtStart()) { - // Move the am/pm view to the beginning - ViewGroup amPmParent = (ViewGroup) findViewById(R.id.timePickerLayout); - amPmParent.removeView(amPmView); - amPmParent.addView(amPmView, 0); - // Swap layout margins if needed. They may be not symmetrical (Old Standard Theme for - // example and not for Holo Theme) - ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) amPmView.getLayoutParams(); - final int startMargin = lp.getMarginStart(); - final int endMargin = lp.getMarginEnd(); - if (startMargin != endMargin) { - lp.setMarginStart(endMargin); - lp.setMarginEnd(startMargin); } - } - getHourFormatData(); + getHourFormatData(); - // update controls to initial state - updateHourControl(); - updateMinuteControl(); - updateAmPmControl(); + // update controls to initial state + updateHourControl(); + updateMinuteControl(); + updateAmPmControl(); - setOnTimeChangedListener(NO_OP_CHANGE_LISTENER); + setOnTimeChangedListener(NO_OP_CHANGE_LISTENER); - // set to current time - setCurrentHour(mTempCalendar.get(Calendar.HOUR_OF_DAY)); - setCurrentMinute(mTempCalendar.get(Calendar.MINUTE)); + // set to current time + setCurrentHour(mTempCalendar.get(Calendar.HOUR_OF_DAY)); + setCurrentMinute(mTempCalendar.get(Calendar.MINUTE)); - if (!isEnabled()) { - setEnabled(false); - } + if (!isEnabled()) { + setEnabled(false); + } - // set the content descriptions - setContentDescriptions(); + // set the content descriptions + setContentDescriptions(); - // If not explicitly specified this view is important for accessibility. - if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { - setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + // If not explicitly specified this view is important for accessibility. + if (mDelegator.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { + mDelegator.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + } } - } - private void getHourFormatData() { - final Locale defaultLocale = Locale.getDefault(); - final String bestDateTimePattern = DateFormat.getBestDateTimePattern(defaultLocale, - (mIs24HourView) ? "Hm" : "hm"); - final int lengthPattern = bestDateTimePattern.length(); - mHourWithTwoDigit = false; - char hourFormat = '\0'; - // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save - // the hour format that we found. - for (int i = 0; i < lengthPattern; i++) { - final char c = bestDateTimePattern.charAt(i); - if (c == 'H' || c == 'h' || c == 'K' || c == 'k') { - mHourFormat = c; - if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) { - mHourWithTwoDigit = true; + private void getHourFormatData() { + final Locale defaultLocale = Locale.getDefault(); + final String bestDateTimePattern = DateFormat.getBestDateTimePattern(defaultLocale, + (mIs24HourView) ? "Hm" : "hm"); + final int lengthPattern = bestDateTimePattern.length(); + mHourWithTwoDigit = false; + char hourFormat = '\0'; + // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save + // the hour format that we found. + for (int i = 0; i < lengthPattern; i++) { + final char c = bestDateTimePattern.charAt(i); + if (c == 'H' || c == 'h' || c == 'K' || c == 'k') { + mHourFormat = c; + if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) { + mHourWithTwoDigit = true; + } + break; } - break; } } - } - private boolean isAmPmAtStart() { - final Locale defaultLocale = Locale.getDefault(); - final String bestDateTimePattern = DateFormat.getBestDateTimePattern(defaultLocale, - "hm" /* skeleton */); + private boolean isAmPmAtStart() { + final Locale defaultLocale = Locale.getDefault(); + final String bestDateTimePattern = DateFormat.getBestDateTimePattern(defaultLocale, + "hm" /* skeleton */); - return bestDateTimePattern.startsWith("a"); - } + return bestDateTimePattern.startsWith("a"); + } - @Override - public void setEnabled(boolean enabled) { - if (mIsEnabled == enabled) { - return; + /** + * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":". + * + * See http://unicode.org/cldr/trac/browser/trunk/common/main + * + * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the + * separator as the character which is just after the hour marker in the returned pattern. + */ + private void setDividerText() { + final Locale defaultLocale = Locale.getDefault(); + final String skeleton = (mIs24HourView) ? "Hm" : "hm"; + final String bestDateTimePattern = DateFormat.getBestDateTimePattern(defaultLocale, + skeleton); + final String separatorText; + int hourIndex = bestDateTimePattern.lastIndexOf('H'); + if (hourIndex == -1) { + hourIndex = bestDateTimePattern.lastIndexOf('h'); + } + if (hourIndex == -1) { + // Default case + separatorText = ":"; + } else { + int minuteIndex = bestDateTimePattern.indexOf('m', hourIndex + 1); + if (minuteIndex == -1) { + separatorText = Character.toString(bestDateTimePattern.charAt(hourIndex + 1)); + } else { + separatorText = bestDateTimePattern.substring(hourIndex + 1, minuteIndex); + } + } + mDivider.setText(separatorText); } - super.setEnabled(enabled); - mMinuteSpinner.setEnabled(enabled); - if (mDivider != null) { - mDivider.setEnabled(enabled); + + @Override + public void setCurrentHour(Integer currentHour) { + // why was Integer used in the first place? + if (currentHour == null || currentHour == getCurrentHour()) { + return; + } + if (!is24HourView()) { + // convert [0,23] ordinal to wall clock display + if (currentHour >= HOURS_IN_HALF_DAY) { + mIsAm = false; + if (currentHour > HOURS_IN_HALF_DAY) { + currentHour = currentHour - HOURS_IN_HALF_DAY; + } + } else { + mIsAm = true; + if (currentHour == 0) { + currentHour = HOURS_IN_HALF_DAY; + } + } + updateAmPmControl(); + } + mHourSpinner.setValue(currentHour); + onTimeChanged(); } - mHourSpinner.setEnabled(enabled); - if (mAmPmSpinner != null) { - mAmPmSpinner.setEnabled(enabled); - } else { - mAmPmButton.setEnabled(enabled); + + @Override + public Integer getCurrentHour() { + int currentHour = mHourSpinner.getValue(); + if (is24HourView()) { + return currentHour; + } else if (mIsAm) { + return currentHour % HOURS_IN_HALF_DAY; + } else { + return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY; + } } - mIsEnabled = enabled; - } - @Override - public boolean isEnabled() { - return mIsEnabled; - } + @Override + public void setCurrentMinute(Integer currentMinute) { + if (currentMinute == getCurrentMinute()) { + return; + } + mMinuteSpinner.setValue(currentMinute); + onTimeChanged(); + } - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - setCurrentLocale(newConfig.locale); - } + @Override + public Integer getCurrentMinute() { + return mMinuteSpinner.getValue(); + } - /** - * Sets the current locale. - * - * @param locale The current locale. - */ - private void setCurrentLocale(Locale locale) { - if (locale.equals(mCurrentLocale)) { - return; + @Override + public void setIs24HourView(Boolean is24HourView) { + if (mIs24HourView == is24HourView) { + return; + } + // cache the current hour since spinner range changes and BEFORE changing mIs24HourView!! + int currentHour = getCurrentHour(); + // Order is important here. + mIs24HourView = is24HourView; + getHourFormatData(); + updateHourControl(); + // set value after spinner range is updated + setCurrentHour(currentHour); + updateMinuteControl(); + updateAmPmControl(); } - mCurrentLocale = locale; - mTempCalendar = Calendar.getInstance(locale); - } - /** - * Used to save / restore state of time picker - */ - private static class SavedState extends BaseSavedState { + @Override + public boolean is24HourView() { + return mIs24HourView; + } - private final int mHour; + @Override + public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) { + mOnTimeChangedListener = onTimeChangedListener; + } - private final int mMinute; + @Override + public void setEnabled(boolean enabled) { + mMinuteSpinner.setEnabled(enabled); + if (mDivider != null) { + mDivider.setEnabled(enabled); + } + mHourSpinner.setEnabled(enabled); + if (mAmPmSpinner != null) { + mAmPmSpinner.setEnabled(enabled); + } else { + mAmPmButton.setEnabled(enabled); + } + mIsEnabled = enabled; + } - private SavedState(Parcelable superState, int hour, int minute) { - super(superState); - mHour = hour; - mMinute = minute; + @Override + public boolean isEnabled() { + return mIsEnabled; } - private SavedState(Parcel in) { - super(in); - mHour = in.readInt(); - mMinute = in.readInt(); + @Override + public int getBaseline() { + return mHourSpinner.getBaseline(); } - public int getHour() { - return mHour; + @Override + public void onConfigurationChanged(Configuration newConfig) { + setCurrentLocale(newConfig.locale); } - public int getMinute() { - return mMinute; + @Override + public Parcelable onSaveInstanceState(Parcelable superState) { + return new SavedState(superState, getCurrentHour(), getCurrentMinute()); } @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeInt(mHour); - dest.writeInt(mMinute); + public void onRestoreInstanceState(Parcelable state) { + SavedState ss = (SavedState) state; + setCurrentHour(ss.getHour()); + setCurrentMinute(ss.getMinute()); } - @SuppressWarnings({"unused", "hiding"}) - public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() { - public SavedState createFromParcel(Parcel in) { - return new SavedState(in); - } + @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + onPopulateAccessibilityEvent(event); + return true; + } - public SavedState[] newArray(int size) { - return new SavedState[size]; + @Override + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + int flags = DateUtils.FORMAT_SHOW_TIME; + if (mIs24HourView) { + flags |= DateUtils.FORMAT_24HOUR; + } else { + flags |= DateUtils.FORMAT_12HOUR; } - }; - } - - @Override - protected Parcelable onSaveInstanceState() { - Parcelable superState = super.onSaveInstanceState(); - return new SavedState(superState, getCurrentHour(), getCurrentMinute()); - } - - @Override - protected void onRestoreInstanceState(Parcelable state) { - SavedState ss = (SavedState) state; - super.onRestoreInstanceState(ss.getSuperState()); - setCurrentHour(ss.getHour()); - setCurrentMinute(ss.getMinute()); - } + mTempCalendar.set(Calendar.HOUR_OF_DAY, getCurrentHour()); + mTempCalendar.set(Calendar.MINUTE, getCurrentMinute()); + String selectedDateUtterance = DateUtils.formatDateTime(mDelegator.getContext(), + mTempCalendar.getTimeInMillis(), flags); + event.getText().add(selectedDateUtterance); + } - /** - * Set the callback that indicates the time has been adjusted by the user. - * - * @param onTimeChangedListener the callback, should not be null. - */ - public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) { - mOnTimeChangedListener = onTimeChangedListener; - } + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + event.setClassName(TimePicker.class.getName()); + } - /** - * @return The current hour in the range (0-23). - */ - public Integer getCurrentHour() { - int currentHour = mHourSpinner.getValue(); - if (is24HourView()) { - return currentHour; - } else if (mIsAm) { - return currentHour % HOURS_IN_HALF_DAY; - } else { - return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY; + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + info.setClassName(TimePicker.class.getName()); } - } - /** - * Set the current hour. - */ - public void setCurrentHour(Integer currentHour) { - // why was Integer used in the first place? - if (currentHour == null || currentHour == getCurrentHour()) { - return; + 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 = InputMethodManager.peekInstance(); + if (inputMethodManager != null) { + if (inputMethodManager.isActive(mHourSpinnerInput)) { + mHourSpinnerInput.clearFocus(); + inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0); + } else if (inputMethodManager.isActive(mMinuteSpinnerInput)) { + mMinuteSpinnerInput.clearFocus(); + inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0); + } else if (inputMethodManager.isActive(mAmPmSpinnerInput)) { + mAmPmSpinnerInput.clearFocus(); + inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0); + } + } } - if (!is24HourView()) { - // convert [0,23] ordinal to wall clock display - if (currentHour >= HOURS_IN_HALF_DAY) { - mIsAm = false; - if (currentHour > HOURS_IN_HALF_DAY) { - currentHour = currentHour - HOURS_IN_HALF_DAY; + + private void updateAmPmControl() { + if (is24HourView()) { + if (mAmPmSpinner != null) { + mAmPmSpinner.setVisibility(View.GONE); + } else { + mAmPmButton.setVisibility(View.GONE); } } else { - mIsAm = true; - if (currentHour == 0) { - currentHour = HOURS_IN_HALF_DAY; + int index = mIsAm ? Calendar.AM : Calendar.PM; + if (mAmPmSpinner != null) { + mAmPmSpinner.setValue(index); + mAmPmSpinner.setVisibility(View.VISIBLE); + } else { + mAmPmButton.setText(mAmPmStrings[index]); + mAmPmButton.setVisibility(View.VISIBLE); } } - updateAmPmControl(); + mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); } - mHourSpinner.setValue(currentHour); - onTimeChanged(); - } - /** - * Set whether in 24 hour or AM/PM mode. - * - * @param is24HourView True = 24 hour mode. False = AM/PM. - */ - public void setIs24HourView(Boolean is24HourView) { - if (mIs24HourView == is24HourView) { - return; + /** + * Sets the current locale. + * + * @param locale The current locale. + */ + private void setCurrentLocale(Locale locale) { + if (locale.equals(mCurrentLocale)) { + return; + } + mCurrentLocale = locale; + mTempCalendar = Calendar.getInstance(locale); } - // cache the current hour since spinner range changes and BEFORE changing mIs24HourView!! - int currentHour = getCurrentHour(); - // Order is important here. - mIs24HourView = is24HourView; - getHourFormatData(); - updateHourControl(); - // set value after spinner range is updated - setCurrentHour(currentHour); - updateMinuteControl(); - updateAmPmControl(); - } - - /** - * @return true if this is in 24 hour view else false. - */ - public boolean is24HourView() { - return mIs24HourView; - } - /** - * @return The current minute. - */ - public Integer getCurrentMinute() { - return mMinuteSpinner.getValue(); - } + private void onTimeChanged() { + mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); + if (mOnTimeChangedListener != null) { + mOnTimeChangedListener.onTimeChanged(mDelegator, getCurrentHour(), + getCurrentMinute()); + } + } - /** - * Set the current minute (0-59). - */ - public void setCurrentMinute(Integer currentMinute) { - if (currentMinute == getCurrentMinute()) { - return; + private void updateHourControl() { + if (is24HourView()) { + // 'k' means 1-24 hour + if (mHourFormat == 'k') { + mHourSpinner.setMinValue(1); + mHourSpinner.setMaxValue(24); + } else { + mHourSpinner.setMinValue(0); + mHourSpinner.setMaxValue(23); + } + } else { + // 'K' means 0-11 hour + if (mHourFormat == 'K') { + mHourSpinner.setMinValue(0); + mHourSpinner.setMaxValue(11); + } else { + mHourSpinner.setMinValue(1); + mHourSpinner.setMaxValue(12); + } + } + mHourSpinner.setFormatter(mHourWithTwoDigit ? NumberPicker.getTwoDigitFormatter() : null); } - mMinuteSpinner.setValue(currentMinute); - onTimeChanged(); - } - /** - * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":". - * - * See http://unicode.org/cldr/trac/browser/trunk/common/main - * - * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the - * separator as the character which is just after the hour marker in the returned pattern. - */ - private void setDividerText() { - final Locale defaultLocale = Locale.getDefault(); - final String skeleton = (mIs24HourView) ? "Hm" : "hm"; - final String bestDateTimePattern = DateFormat.getBestDateTimePattern(defaultLocale, - skeleton); - final String separatorText; - int hourIndex = bestDateTimePattern.lastIndexOf('H'); - if (hourIndex == -1) { - hourIndex = bestDateTimePattern.lastIndexOf('h'); - } - if (hourIndex == -1) { - // Default case - separatorText = ":"; - } else { - int minuteIndex = bestDateTimePattern.indexOf('m', hourIndex + 1); - if (minuteIndex == -1) { - separatorText = Character.toString(bestDateTimePattern.charAt(hourIndex + 1)); + private void updateMinuteControl() { + if (is24HourView()) { + mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE); } else { - separatorText = bestDateTimePattern.substring(hourIndex + 1, minuteIndex); + mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT); } } - mDivider.setText(separatorText); - } - @Override - public int getBaseline() { - return mHourSpinner.getBaseline(); - } + private void setContentDescriptions() { + // Minute + trySetContentDescription(mMinuteSpinner, R.id.increment, + R.string.time_picker_increment_minute_button); + trySetContentDescription(mMinuteSpinner, R.id.decrement, + R.string.time_picker_decrement_minute_button); + // Hour + trySetContentDescription(mHourSpinner, R.id.increment, + R.string.time_picker_increment_hour_button); + trySetContentDescription(mHourSpinner, R.id.decrement, + R.string.time_picker_decrement_hour_button); + // AM/PM + if (mAmPmSpinner != null) { + trySetContentDescription(mAmPmSpinner, R.id.increment, + R.string.time_picker_increment_set_pm_button); + trySetContentDescription(mAmPmSpinner, R.id.decrement, + R.string.time_picker_decrement_set_am_button); + } + } - @Override - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - onPopulateAccessibilityEvent(event); - return true; + private void trySetContentDescription(View root, int viewId, int contDescResId) { + View target = root.findViewById(viewId); + if (target != null) { + target.setContentDescription(mDelegator.getContext().getString(contDescResId)); + } + } } - @Override - public void onPopulateAccessibilityEvent(AccessibilityEvent event) { - super.onPopulateAccessibilityEvent(event); - - int flags = DateUtils.FORMAT_SHOW_TIME; - if (mIs24HourView) { - flags |= DateUtils.FORMAT_24HOUR; - } else { - flags |= DateUtils.FORMAT_12HOUR; - } - mTempCalendar.set(Calendar.HOUR_OF_DAY, getCurrentHour()); - mTempCalendar.set(Calendar.MINUTE, getCurrentMinute()); - String selectedDateUtterance = DateUtils.formatDateTime(mContext, - mTempCalendar.getTimeInMillis(), flags); - event.getText().add(selectedDateUtterance); - } + /** + * Used to save / restore state of time picker + */ + private static class SavedState extends BaseSavedState { - @Override - public void onInitializeAccessibilityEvent(AccessibilityEvent event) { - super.onInitializeAccessibilityEvent(event); - event.setClassName(TimePicker.class.getName()); - } + private final int mHour; - @Override - public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(info); - info.setClassName(TimePicker.class.getName()); - } + private final int mMinute; - private void updateHourControl() { - if (is24HourView()) { - // 'k' means 1-24 hour - if (mHourFormat == 'k') { - mHourSpinner.setMinValue(1); - mHourSpinner.setMaxValue(24); - } else { - mHourSpinner.setMinValue(0); - mHourSpinner.setMaxValue(23); - } - } else { - // 'K' means 0-11 hour - if (mHourFormat == 'K') { - mHourSpinner.setMinValue(0); - mHourSpinner.setMaxValue(11); - } else { - mHourSpinner.setMinValue(1); - mHourSpinner.setMaxValue(12); - } + private SavedState(Parcelable superState, int hour, int minute) { + super(superState); + mHour = hour; + mMinute = minute; } - mHourSpinner.setFormatter(mHourWithTwoDigit ? NumberPicker.getTwoDigitFormatter() : null); - } - private void updateMinuteControl() { - if (is24HourView()) { - mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE); - } else { - mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT); + private SavedState(Parcel in) { + super(in); + mHour = in.readInt(); + mMinute = in.readInt(); } - } - private void updateAmPmControl() { - if (is24HourView()) { - if (mAmPmSpinner != null) { - mAmPmSpinner.setVisibility(View.GONE); - } else { - mAmPmButton.setVisibility(View.GONE); - } - } else { - int index = mIsAm ? Calendar.AM : Calendar.PM; - if (mAmPmSpinner != null) { - mAmPmSpinner.setValue(index); - mAmPmSpinner.setVisibility(View.VISIBLE); - } else { - mAmPmButton.setText(mAmPmStrings[index]); - mAmPmButton.setVisibility(View.VISIBLE); - } + public int getHour() { + return mHour; } - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); - } - private void onTimeChanged() { - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); - if (mOnTimeChangedListener != null) { - mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute()); + public int getMinute() { + return mMinute; } - } - private void setContentDescriptions() { - // Minute - trySetContentDescription(mMinuteSpinner, R.id.increment, - R.string.time_picker_increment_minute_button); - trySetContentDescription(mMinuteSpinner, R.id.decrement, - R.string.time_picker_decrement_minute_button); - // Hour - trySetContentDescription(mHourSpinner, R.id.increment, - R.string.time_picker_increment_hour_button); - trySetContentDescription(mHourSpinner, R.id.decrement, - R.string.time_picker_decrement_hour_button); - // AM/PM - if (mAmPmSpinner != null) { - trySetContentDescription(mAmPmSpinner, R.id.increment, - R.string.time_picker_increment_set_pm_button); - trySetContentDescription(mAmPmSpinner, R.id.decrement, - R.string.time_picker_decrement_set_am_button); + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(mHour); + dest.writeInt(mMinute); } - } - private void trySetContentDescription(View root, int viewId, int contDescResId) { - View target = root.findViewById(viewId); - if (target != null) { - target.setContentDescription(mContext.getString(contDescResId)); - } - } + @SuppressWarnings({"unused", "hiding"}) + public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } - 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 = InputMethodManager.peekInstance(); - if (inputMethodManager != null) { - if (inputMethodManager.isActive(mHourSpinnerInput)) { - mHourSpinnerInput.clearFocus(); - inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); - } else if (inputMethodManager.isActive(mMinuteSpinnerInput)) { - mMinuteSpinnerInput.clearFocus(); - inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); - } else if (inputMethodManager.isActive(mAmPmSpinnerInput)) { - mAmPmSpinnerInput.clearFocus(); - inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); + public SavedState[] newArray(int size) { + return new SavedState[size]; } - } + }; } } |