diff options
| author | 2017-08-10 18:38:44 -0700 | |
|---|---|---|
| committer | 2017-08-15 10:42:58 -0700 | |
| commit | f480e8cad5e6cf4fed85a944adc01d96f51e966b (patch) | |
| tree | b397ded5cfbc6eb89f0085fd880e1e81d290691f | |
| parent | 144d8cb6261b831bebcd2adb1ed73c1e9298190a (diff) | |
Improved autofill support on DatePicker and TimePicker:
- Save autofilled value so UI is properly highlighted.
- Notify TimePicker listener just once.
Test: cts-tradefed run commandAndExit cts-dev -m CtsAutoFillServiceTestCases
Test: cts-tradefed run commandAndExit cts-dev -m CtsWidgetTestCases -t android.widget.cts.DatePickerTest
Test: cts-tradefed run commandAndExit cts-dev -m CtsWidgetTestCases -t android.widget.cts.TimePickerTest
Fixes: 37098837
Change-Id: I38d64c107f6059b94c92676ea37681006474f519
| -rw-r--r-- | core/java/android/widget/DatePicker.java | 52 | ||||
| -rwxr-xr-x | core/java/android/widget/DatePickerCalendarDelegate.java | 15 | ||||
| -rw-r--r-- | core/java/android/widget/DatePickerSpinnerDelegate.java | 1 | ||||
| -rw-r--r-- | core/java/android/widget/TimePicker.java | 59 | ||||
| -rw-r--r-- | core/java/android/widget/TimePickerClockDelegate.java | 35 | ||||
| -rw-r--r-- | core/java/android/widget/TimePickerSpinnerDelegate.java | 18 |
6 files changed, 131 insertions, 49 deletions
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index 8094bfc6eeb8..dfb36423ea94 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -524,12 +524,13 @@ public class DatePicker extends FrameLayout { void setAutoFillChangeListener(OnDateChangedListener onDateChangedListener); void updateDate(int year, int month, int dayOfMonth); - void updateDate(long date); int getYear(); int getMonth(); int getDayOfMonth(); - long getDate(); + + void autofill(AutofillValue value); + AutofillValue getAutofillValue(); void setFirstDayOfWeek(int firstDayOfWeek); int getFirstDayOfWeek(); @@ -572,6 +573,7 @@ public class DatePicker extends FrameLayout { // The context protected Context mContext; + // NOTE: when subclasses change this variable, they must call resetAutofilledValue(). protected Calendar mCurrentDate; // The current locale @@ -582,6 +584,11 @@ public class DatePicker extends FrameLayout { protected OnDateChangedListener mAutoFillChangeListener; protected ValidationCallback mValidationCallback; + // The value that was passed to autofill() - it must be stored because it getAutofillValue() + // must return the exact same value that was autofilled, otherwise the widget will not be + // properly highlighted after autofill(). + private long mAutofilledValue; + public AbstractDatePickerDelegate(DatePicker delegator, Context context) { mDelegator = delegator; mContext = context; @@ -612,16 +619,38 @@ public class DatePicker extends FrameLayout { } @Override - public void updateDate(long date) { - Calendar cal = Calendar.getInstance(mCurrentLocale); - cal.setTimeInMillis(date); + public final void autofill(AutofillValue value) { + if (value == null || !value.isDate()) { + Log.w(LOG_TAG, value + " could not be autofilled into " + this); + return; + } + + final long time = value.getDateValue(); + + final Calendar cal = Calendar.getInstance(mCurrentLocale); + cal.setTimeInMillis(time); updateDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)); + + // Must set mAutofilledValue *after* calling subclass method to make sure the value + // returned by getAutofillValue() matches it. + mAutofilledValue = time; } @Override - public long getDate() { - return mCurrentDate.getTimeInMillis(); + public final AutofillValue getAutofillValue() { + final long time = mAutofilledValue != 0 + ? mAutofilledValue + : mCurrentDate.getTimeInMillis(); + return AutofillValue.forDate(time); + } + + /** + * This method must be called every time the value of the year, month, and/or day is + * changed by a subclass method. + */ + protected void resetAutofilledValue() { + mAutofilledValue = 0; } protected void onValidationChanged(boolean valid) { @@ -777,12 +806,7 @@ public class DatePicker extends FrameLayout { public void autofill(AutofillValue value) { if (!isEnabled()) return; - if (!value.isDate()) { - Log.w(LOG_TAG, value + " could not be autofilled into " + this); - return; - } - - mDelegate.updateDate(value.getDateValue()); + mDelegate.autofill(value); } @Override @@ -792,6 +816,6 @@ public class DatePicker extends FrameLayout { @Override public AutofillValue getAutofillValue() { - return isEnabled() ? AutofillValue.forDate(mDelegate.getDate()) : null; + return isEnabled() ? mDelegate.getAutofillValue() : null; } } diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java index 636519b197e7..60b4757216af 100755 --- a/core/java/android/widget/DatePickerCalendarDelegate.java +++ b/core/java/android/widget/DatePickerCalendarDelegate.java @@ -368,12 +368,9 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate { } @Override - public void init(int year, int monthOfYear, int dayOfMonth, + public void init(int year, int month, int dayOfMonth, DatePicker.OnDateChangedListener callBack) { - mCurrentDate.set(Calendar.YEAR, year); - mCurrentDate.set(Calendar.MONTH, monthOfYear); - mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); - + setDate(year, month, dayOfMonth); onDateChanged(false, false); mOnDateChangedListener = callBack; @@ -381,11 +378,15 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate { @Override public void updateDate(int year, int month, int dayOfMonth) { + setDate(year, month, dayOfMonth); + onDateChanged(false, true); + } + + private void setDate(int year, int month, int dayOfMonth) { mCurrentDate.set(Calendar.YEAR, year); mCurrentDate.set(Calendar.MONTH, month); mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); - - onDateChanged(false, true); + resetAutofilledValue(); } private void onDateChanged(boolean fromUser, boolean callbackToClient) { diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java index 4f9316f881cd..dba74b191b09 100644 --- a/core/java/android/widget/DatePickerSpinnerDelegate.java +++ b/core/java/android/widget/DatePickerSpinnerDelegate.java @@ -504,6 +504,7 @@ class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate { 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)) { diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index de289bb9a27a..ae6881e4e28c 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -366,8 +366,11 @@ public class TimePicker extends FrameLayout { void setMinute(@IntRange(from = 0, to = 59) int minute); int getMinute(); - void setDate(long date); - long getDate(); + void setDate(@IntRange(from = 0, to = 23) int hour, + @IntRange(from = 0, to = 59) int minute); + + void autofill(AutofillValue value); + AutofillValue getAutofillValue(); void setIs24Hour(boolean is24Hour); boolean is24Hour(); @@ -422,6 +425,11 @@ public class TimePicker extends FrameLayout { protected OnTimeChangedListener mOnTimeChangedListener; protected OnTimeChangedListener mAutoFillChangeListener; + // The value that was passed to autofill() - it must be stored because it getAutofillValue() + // must return the exact same value that was autofilled, otherwise the widget will not be + // properly highlighted after autofill(). + private long mAutofilledValue; + public AbstractTimePickerDelegate(@NonNull TimePicker delegator, @NonNull Context context) { mDelegator = delegator; mContext = context; @@ -439,19 +447,41 @@ public class TimePicker extends FrameLayout { } @Override - public void setDate(long date) { - Calendar cal = Calendar.getInstance(mLocale); - cal.setTimeInMillis(date); - setHour(cal.get(Calendar.HOUR_OF_DAY)); - setMinute(cal.get(Calendar.MINUTE)); + public final void autofill(AutofillValue value) { + if (value == null || !value.isDate()) { + Log.w(LOG_TAG, value + " could not be autofilled into " + this); + return; + } + + final long time = value.getDateValue(); + + final Calendar cal = Calendar.getInstance(mLocale); + cal.setTimeInMillis(time); + setDate(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE)); + + // Must set mAutofilledValue *after* calling subclass method to make sure the value + // returned by getAutofillValue() matches it. + mAutofilledValue = time; } @Override - public long getDate() { - Calendar cal = Calendar.getInstance(mLocale); + public final AutofillValue getAutofillValue() { + if (mAutofilledValue != 0) { + return AutofillValue.forDate(mAutofilledValue); + } + + final Calendar cal = Calendar.getInstance(mLocale); cal.set(Calendar.HOUR_OF_DAY, getHour()); cal.set(Calendar.MINUTE, getMinute()); - return cal.getTimeInMillis(); + return AutofillValue.forDate(cal.getTimeInMillis()); + } + + /** + * This method must be called every time the value of the hour and/or minute is changed by + * a subclass method. + */ + protected void resetAutofilledValue() { + mAutofilledValue = 0; } protected static class SavedState extends View.BaseSavedState { @@ -532,12 +562,7 @@ public class TimePicker extends FrameLayout { public void autofill(AutofillValue value) { if (!isEnabled()) return; - if (!value.isDate()) { - Log.w(LOG_TAG, value + " could not be autofilled into " + this); - return; - } - - mDelegate.setDate(value.getDateValue()); + mDelegate.autofill(value); } @Override @@ -547,6 +572,6 @@ public class TimePicker extends FrameLayout { @Override public AutofillValue getAutofillValue() { - return isEnabled() ? AutofillValue.forDate(mDelegate.getDate()) : null; + return isEnabled() ? mDelegate.getAutofillValue() : null; } } diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java index 526246b28530..706b0ce225dc 100644 --- a/core/java/android/widget/TimePickerClockDelegate.java +++ b/core/java/android/widget/TimePickerClockDelegate.java @@ -506,19 +506,29 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { mAmPmLayout.setLayoutParams(params); } + @Override + public void setDate(int hour, int minute) { + setHourInternal(hour, FROM_EXTERNAL_API, true, false); + setMinuteInternal(minute, FROM_EXTERNAL_API, false); + + onTimeChanged(); + } + /** * Set the current hour. */ @Override public void setHour(int hour) { - setHourInternal(hour, FROM_EXTERNAL_API, true); + setHourInternal(hour, FROM_EXTERNAL_API, true, true); } - private void setHourInternal(int hour, @ChangeSource int source, boolean announce) { + private void setHourInternal(int hour, @ChangeSource int source, boolean announce, + boolean notify) { if (mCurrentHour == hour) { return; } + resetAutofilledValue(); mCurrentHour = hour; updateHeaderHour(hour, announce); updateHeaderAmPm(); @@ -532,7 +542,9 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { } mDelegator.invalidate(); - onTimeChanged(); + if (notify) { + onTimeChanged(); + } } /** @@ -557,14 +569,15 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { */ @Override public void setMinute(int minute) { - setMinuteInternal(minute, FROM_EXTERNAL_API); + setMinuteInternal(minute, FROM_EXTERNAL_API, true); } - private void setMinuteInternal(int minute, @ChangeSource int source) { + private void setMinuteInternal(int minute, @ChangeSource int source, boolean notify) { if (mCurrentMinute == minute) { return; } + resetAutofilledValue(); mCurrentMinute = minute; updateHeaderMinute(minute, true); @@ -576,7 +589,9 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { } mDelegator.invalidate(); - onTimeChanged(); + if (notify) { + onTimeChanged(); + } } /** @@ -870,7 +885,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { valueChanged = true; } final boolean isTransition = mAllowAutoAdvance && autoAdvance; - setHourInternal(newValue, FROM_RADIAL_PICKER, !isTransition); + setHourInternal(newValue, FROM_RADIAL_PICKER, !isTransition, true); if (isTransition) { setCurrentItemShowing(MINUTE_INDEX, true, false); @@ -882,7 +897,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { if (getMinute() != newValue) { valueChanged = true; } - setMinuteInternal(newValue, FROM_RADIAL_PICKER); + setMinuteInternal(newValue, FROM_RADIAL_PICKER, true); break; } @@ -897,10 +912,10 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { public void onValueChanged(int pickerType, int newValue) { switch (pickerType) { case TextInputTimePickerView.HOURS: - setHourInternal(newValue, FROM_INPUT_PICKER, false); + setHourInternal(newValue, FROM_INPUT_PICKER, false, true); break; case TextInputTimePickerView.MINUTES: - setMinuteInternal(newValue, FROM_INPUT_PICKER); + setMinuteInternal(newValue, FROM_INPUT_PICKER, true); break; case TextInputTimePickerView.AMPM: setAmOrPm(newValue); diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java index 7a7d9a948dcc..cc79b9c85784 100644 --- a/core/java/android/widget/TimePickerSpinnerDelegate.java +++ b/core/java/android/widget/TimePickerSpinnerDelegate.java @@ -284,6 +284,14 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate { } @Override + public void setDate(int hour, int minute) { + setCurrentHour(hour, false); + setCurrentMinute(minute, false); + + onTimeChanged(); + } + + @Override public void setHour(int hour) { setCurrentHour(hour, true); } @@ -293,6 +301,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate { if (currentHour == getHour()) { return; } + resetAutofilledValue(); if (!is24Hour()) { // convert [0,23] ordinal to wall clock display if (currentHour >= HOURS_IN_HALF_DAY) { @@ -328,11 +337,18 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate { @Override public void setMinute(int minute) { + setCurrentMinute(minute, true); + } + + private void setCurrentMinute(int minute, boolean notifyTimeChanged) { if (minute == getMinute()) { return; } + resetAutofilledValue(); mMinuteSpinner.setValue(minute); - onTimeChanged(); + if (notifyTimeChanged) { + onTimeChanged(); + } } @Override |