Merge "Improved autofill support on DatePicker and TimePicker:" into oc-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
6598a4ed52
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -283,6 +283,14 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
mDivider.setText(separatorText);
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
Reference in New Issue
Block a user