Merge "DatePicker crashes when going from 2036 to 2035 via ▼" into ics-mr0

This commit is contained in:
Svetoslav Ganov
2011-10-19 21:15:30 -07:00
committed by Android (Google) Code Review
3 changed files with 88 additions and 21 deletions

View File

@ -32,6 +32,7 @@ import android.view.LayoutInflater;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.NumberPicker.OnValueChangeListener;
import com.android.internal.R;
@ -90,6 +91,12 @@ public class DatePicker extends FrameLayout {
private final NumberPicker mYearSpinner;
private final EditText mDaySpinnerInput;
private final EditText mMonthSpinnerInput;
private final EditText mYearSpinnerInput;
private final CalendarView mCalendarView;
private Locale mCurrentLocale;
@ -164,6 +171,7 @@ public class DatePicker extends FrameLayout {
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) {
@ -214,6 +222,7 @@ public class DatePicker extends FrameLayout {
mDaySpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
mDaySpinner.setOnLongPressUpdateInterval(100);
mDaySpinner.setOnValueChangedListener(onChangeListener);
mDaySpinnerInput = (EditText) mDaySpinner.findViewById(R.id.numberpicker_input);
// month
mMonthSpinner = (NumberPicker) findViewById(R.id.month);
@ -222,11 +231,13 @@ public class DatePicker extends FrameLayout {
mMonthSpinner.setDisplayedValues(mShortMonths);
mMonthSpinner.setOnLongPressUpdateInterval(200);
mMonthSpinner.setOnValueChangedListener(onChangeListener);
mMonthSpinnerInput = (EditText) mMonthSpinner.findViewById(R.id.numberpicker_input);
// year
mYearSpinner = (NumberPicker) findViewById(R.id.year);
mYearSpinner.setOnLongPressUpdateInterval(100);
mYearSpinner.setOnValueChangedListener(onChangeListener);
mYearSpinnerInput = (EditText) mYearSpinner.findViewById(R.id.numberpicker_input);
// show only what the user required but make sure we
// show something and the spinners have higher priority
@ -709,6 +720,27 @@ public class DatePicker extends FrameLayout {
mYearSpinner.findViewById(R.id.decrement).setContentDescription(text);
}
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(mYearSpinnerInput)) {
mYearSpinnerInput.clearFocus();
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
} else if (inputMethodManager.isActive(mMonthSpinnerInput)) {
mMonthSpinnerInput.clearFocus();
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
} else if (inputMethodManager.isActive(mDaySpinnerInput)) {
mDaySpinnerInput.clearFocus();
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
}
}
}
/**
* Class for managing state storing/restoring.
*/

View File

@ -536,6 +536,10 @@ public class NumberPicker extends LinearLayout {
OnClickListener onClickListener = new OnClickListener() {
public void onClick(View v) {
InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
if (inputMethodManager != null && inputMethodManager.isActive(mInputText)) {
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
}
mInputText.clearFocus();
if (v.getId() == R.id.increment) {
changeCurrentByOne(true);
@ -571,17 +575,14 @@ public class NumberPicker extends LinearLayout {
mInputText = (EditText) findViewById(R.id.numberpicker_input);
mInputText.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
if (hasFocus) {
mInputText.selectAll();
InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
if (inputMethodManager != null) {
inputMethodManager.showSoftInput(mInputText, 0);
}
} else {
mInputText.setSelection(0, 0);
if (inputMethodManager != null) {
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
}
validateInputTextView(v);
}
}
@ -996,17 +997,14 @@ public class NumberPicker extends LinearLayout {
* enabled.
* </p>
*
* @param wrapSelector Whether to wrap.
* @param wrapSelectorWheel Whether to wrap.
*/
public void setWrapSelectorWheel(boolean wrapSelector) {
if (wrapSelector && (mMaxValue - mMinValue) < mSelectorIndices.length) {
public void setWrapSelectorWheel(boolean wrapSelectorWheel) {
if (wrapSelectorWheel && (mMaxValue - mMinValue) < mSelectorIndices.length) {
throw new IllegalStateException("Range less than selector items count.");
}
if (wrapSelector != mWrapSelectorWheel) {
// force the selector indices array to be reinitialized
mSelectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] = Integer.MAX_VALUE;
mWrapSelectorWheel = wrapSelector;
// force redraw since we might look different
if (wrapSelectorWheel != mWrapSelectorWheel) {
mWrapSelectorWheel = wrapSelectorWheel;
updateIncrementAndDecrementButtonsVisibilityState();
}
}
@ -1206,7 +1204,13 @@ public class NumberPicker extends LinearLayout {
for (int i = 0; i < selectorIndices.length; i++) {
int selectorIndex = selectorIndices[i];
String scrollSelectorValue = mSelectorIndexToStringCache.get(selectorIndex);
canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint);
// Do not draw the middle item if input is visible since the input is shown only
// if the wheel is static and it covers the middle item. Otherwise, if the user
// starts editing the text via the IME he may see a dimmed version of the old
// value intermixed with the new one.
if (i != SELECTOR_MIDDLE_ITEM_INDEX || mInputText.getVisibility() != VISIBLE) {
canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint);
}
y += mSelectorElementHeight;
}

View File

@ -27,8 +27,8 @@ import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.NumberPicker.OnValueChangeListener;
import com.android.internal.R;
@ -79,6 +79,12 @@ public class TimePicker extends FrameLayout {
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
@ -140,6 +146,7 @@ public class TimePicker extends FrameLayout {
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)) {
@ -150,8 +157,8 @@ public class TimePicker extends FrameLayout {
onTimeChanged();
}
});
EditText hourInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input);
hourInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
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);
@ -167,6 +174,7 @@ public class TimePicker extends FrameLayout {
mMinuteSpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
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) {
@ -187,8 +195,8 @@ public class TimePicker extends FrameLayout {
onTimeChanged();
}
});
EditText minuteInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
minuteInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
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();
@ -197,6 +205,7 @@ public class TimePicker extends FrameLayout {
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) {
@ -213,13 +222,14 @@ public class TimePicker extends FrameLayout {
mAmPmSpinner.setDisplayedValues(mAmPmStrings);
mAmPmSpinner.setOnValueChangedListener(new OnValueChangeListener() {
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
updateInputState();
picker.requestFocus();
mIsAm = !mIsAm;
updateAmPmControl();
}
});
EditText amPmInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
amPmInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
}
// update controls to initial state
@ -319,7 +329,7 @@ public class TimePicker extends FrameLayout {
dest.writeInt(mMinute);
}
@SuppressWarnings("unused")
@SuppressWarnings({"unused", "hiding"})
public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
@ -524,4 +534,25 @@ public class TimePicker extends FrameLayout {
mAmPmSpinner.findViewById(R.id.decrement).setContentDescription(text);
}
}
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);
}
}
}
}