Merge "Improved autofill support on DatePicker and TimePicker:" into oc-mr1-dev

am: 6598a4ed52

Change-Id: I525f68f43616d758ef8f9c4e21afd191d7325917
This commit is contained in:
Felipe Leme
2017-08-16 22:51:52 +00:00
committed by android-build-merger
6 changed files with 131 additions and 49 deletions

View File

@@ -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;
}
}

View File

@@ -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) {

View File

@@ -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)) {

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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