diff --git a/api/current.txt b/api/current.txt index 445c576cf091e..d38ef3dc6ab55 100644 --- a/api/current.txt +++ b/api/current.txt @@ -47095,10 +47095,12 @@ package android.view.autofill { public final class AutoFillType implements android.os.Parcelable { method public int describeContents(); + method public static android.view.autofill.AutoFillType forDate(); method public static android.view.autofill.AutoFillType forList(); method public static android.view.autofill.AutoFillType forText(int); method public static android.view.autofill.AutoFillType forToggle(); method public int getSubType(); + method public boolean isDate(); method public boolean isList(); method public boolean isText(); method public boolean isToggle(); @@ -47108,9 +47110,11 @@ package android.view.autofill { public final class AutoFillValue implements android.os.Parcelable { method public int describeContents(); + method public static android.view.autofill.AutoFillValue forDate(long); method public static android.view.autofill.AutoFillValue forList(int); method public static android.view.autofill.AutoFillValue forText(java.lang.CharSequence); method public static android.view.autofill.AutoFillValue forToggle(boolean); + method public long getDateValue(); method public int getListValue(); method public java.lang.CharSequence getTextValue(); method public boolean getToggleValue(); diff --git a/api/system-current.txt b/api/system-current.txt index e00507ee884cb..94f3c01a301fe 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -50443,10 +50443,12 @@ package android.view.autofill { public final class AutoFillType implements android.os.Parcelable { method public int describeContents(); + method public static android.view.autofill.AutoFillType forDate(); method public static android.view.autofill.AutoFillType forList(); method public static android.view.autofill.AutoFillType forText(int); method public static android.view.autofill.AutoFillType forToggle(); method public int getSubType(); + method public boolean isDate(); method public boolean isList(); method public boolean isText(); method public boolean isToggle(); @@ -50456,9 +50458,11 @@ package android.view.autofill { public final class AutoFillValue implements android.os.Parcelable { method public int describeContents(); + method public static android.view.autofill.AutoFillValue forDate(long); method public static android.view.autofill.AutoFillValue forList(int); method public static android.view.autofill.AutoFillValue forText(java.lang.CharSequence); method public static android.view.autofill.AutoFillValue forToggle(boolean); + method public long getDateValue(); method public int getListValue(); method public java.lang.CharSequence getTextValue(); method public boolean getToggleValue(); diff --git a/api/test-current.txt b/api/test-current.txt index 500a0569bfd2e..4b47ed28956a7 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -47459,10 +47459,12 @@ package android.view.autofill { public final class AutoFillType implements android.os.Parcelable { method public int describeContents(); + method public static android.view.autofill.AutoFillType forDate(); method public static android.view.autofill.AutoFillType forList(); method public static android.view.autofill.AutoFillType forText(int); method public static android.view.autofill.AutoFillType forToggle(); method public int getSubType(); + method public boolean isDate(); method public boolean isList(); method public boolean isText(); method public boolean isToggle(); @@ -47472,9 +47474,11 @@ package android.view.autofill { public final class AutoFillValue implements android.os.Parcelable { method public int describeContents(); + method public static android.view.autofill.AutoFillValue forDate(long); method public static android.view.autofill.AutoFillValue forList(int); method public static android.view.autofill.AutoFillValue forText(java.lang.CharSequence); method public static android.view.autofill.AutoFillValue forToggle(boolean); + method public long getDateValue(); method public int getListValue(); method public java.lang.CharSequence getTextValue(); method public boolean getToggleValue(); diff --git a/core/java/android/view/autofill/AutoFillType.java b/core/java/android/view/autofill/AutoFillType.java index 5d85bfdac095b..e974705178335 100644 --- a/core/java/android/view/autofill/AutoFillType.java +++ b/core/java/android/view/autofill/AutoFillType.java @@ -40,18 +40,13 @@ public final class AutoFillType implements Parcelable { private static class DefaultTypesHolder { static final AutoFillType TOGGLE = new AutoFillType(TYPE_TOGGLE, 0); static final AutoFillType LIST = new AutoFillType(TYPE_LIST, 0); + static final AutoFillType DATE = new AutoFillType(TYPE_DATE, 0); } private static final int TYPE_TEXT = 1; private static final int TYPE_TOGGLE = 2; private static final int TYPE_LIST = 3; - - // TODO(b/33197203): add others, like date picker? That would be trick, because they're set as: - // updateDate(int year, int month, int dayOfMonth) - // So, we would have to either use a long representing the Date.time(), or a custom long - // representing: - // year * 10000 + month * 100 + day - // Then a custom getDatePickerValue(Bundle) that returns an immutable object with these 3 fields + private static final int TYPE_DATE = 4; private final int mType; private final int mSubType; @@ -65,7 +60,7 @@ public final class AutoFillType implements Parcelable { * Checks if this is a type for a text field, which is filled by a {@link CharSequence}. * *
{@link AutoFillValue} instances for auto-filling a {@link View} can be obtained through - * {@link AutoFillValue#forText(CharSequence)}, and the value of a bundle passed to auto-fill a + * {@link AutoFillValue#forText(CharSequence)}, and the value passed to auto-fill a * {@link View} can be fetched through {@link AutoFillValue#getTextValue()}. * *
Sub-type for this type is the value defined by {@link TextView#getInputType()}. @@ -78,7 +73,7 @@ public final class AutoFillType implements Parcelable { * Checks if this is a a type for a togglable field, which is filled by a {@code boolean}. * *
{@link AutoFillValue} instances for auto-filling a {@link View} can be obtained through - * {@link AutoFillValue#forToggle(boolean)}, and the value of a bundle passed to auto-fill a + * {@link AutoFillValue#forToggle(boolean)}, and the value passed to auto-fill a * {@link View} can be fetched through {@link AutoFillValue#getToggleValue()}. * *
This type has no sub-types. @@ -92,7 +87,7 @@ public final class AutoFillType implements Parcelable { * representing the element index inside the list (starting at {@code 0}. * *
{@link AutoFillValue} instances for auto-filling a {@link View} can be obtained through - * {@link AutoFillValue#forList(int)}, and the value of a bundle passed to auto-fill a + * {@link AutoFillValue#forList(int)}, and the value passed to auto-fill a * {@link View} can be fetched through {@link AutoFillValue#getListValue()}. * *
This type has no sub-types. @@ -101,6 +96,20 @@ public final class AutoFillType implements Parcelable { return mType == TYPE_LIST; } + /** + * Checks if this is a type for a date and time, which is represented by a long representing + * the number of milliseconds since the standard base time known as "the epoch", namely + * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. + * + *
{@link AutoFillValue} instances for auto-filling a {@link View} can be obtained through + * {@link AutoFillValue#forDate(long)}, and the values passed to + * auto-fill a {@link View} can be fetched through {@link AutoFillValue#getDateValue()}. + * + *
This type has no sub-types. + */ + public boolean isDate() { + return mType == TYPE_DATE; + } /** * Gets the optional sub-type, representing the {@link View}'s semantic. @@ -206,4 +215,13 @@ public final class AutoFillType implements Parcelable { public static AutoFillType forList() { return DefaultTypesHolder.LIST; } + + /** + * Creates a type that represents a date. + * + *
See {@link #isDate()} for more info. + */ + public static AutoFillType forDate() { + return DefaultTypesHolder.DATE; + } } diff --git a/core/java/android/view/autofill/AutoFillValue.java b/core/java/android/view/autofill/AutoFillValue.java index d9afa3ba2dee5..c24e04e50154b 100644 --- a/core/java/android/view/autofill/AutoFillValue.java +++ b/core/java/android/view/autofill/AutoFillValue.java @@ -35,11 +35,13 @@ public final class AutoFillValue implements Parcelable { private final String mText; private final int mListIndex; private final boolean mToggle; + private final long mDate; - private AutoFillValue(CharSequence text, int listIndex, boolean toggle) { + private AutoFillValue(CharSequence text, int listIndex, boolean toggle, long date) { mText = (text == null) ? null : text.toString(); mListIndex = listIndex; mToggle = toggle; + mDate = date; } /** @@ -69,6 +71,17 @@ public final class AutoFillValue implements Parcelable { return mListIndex; } + /** + * Gets the value representing the the number of milliseconds since the standard base time known + * as "the epoch", namely January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()} + * of a date field. + * + *
See {@link AutoFillType#isDate()} for more info.
+ */
+ public long getDateValue() {
+ return mDate;
+ }
+
/////////////////////////////////////
// Object "contract" methods. //
/////////////////////////////////////
@@ -77,9 +90,10 @@ public final class AutoFillValue implements Parcelable {
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + mListIndex;
result = prime * result + ((mText == null) ? 0 : mText.hashCode());
+ result = prime * result + mListIndex;
result = prime * result + (mToggle ? 1231 : 1237);
+ result = prime * result + (int) (mDate ^ (mDate >>> 32));
return result;
}
@@ -89,13 +103,14 @@ public final class AutoFillValue implements Parcelable {
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final AutoFillValue other = (AutoFillValue) obj;
- if (mListIndex != other.mListIndex) return false;
if (mText == null) {
if (other.mText != null) return false;
} else {
if (!mText.equals(other.mText)) return false;
}
+ if (mListIndex != other.mListIndex) return false;
if (mToggle != other.mToggle) return false;
+ if (mDate != other.mDate) return false;
return true;
}
@@ -113,7 +128,7 @@ public final class AutoFillValue implements Parcelable {
return mText.length() + "_chars";
}
- return "[listIndex=" + mListIndex + ", toggle=" + mToggle + "]";
+ return "[l=" + mListIndex + ", t=" + mToggle + ", d=" + mDate + "]";
}
/////////////////////////////////////
@@ -130,12 +145,14 @@ public final class AutoFillValue implements Parcelable {
parcel.writeString(mText);
parcel.writeInt(mListIndex);
parcel.writeInt(mToggle ? 1 : 0);
+ parcel.writeLong(mDate);
}
private AutoFillValue(Parcel parcel) {
mText = parcel.readString();
mListIndex = parcel.readInt();
mToggle = parcel.readInt() == 1;
+ mDate = parcel.readLong();
}
public static final Parcelable.Creator See {@link AutoFillType#isText()} for more info.
*/
// TODO(b/33197203): use cache
@Nullable
public static AutoFillValue forText(@Nullable CharSequence value) {
- return value == null ? null : new AutoFillValue(value, 0, false);
+ return value == null ? null : new AutoFillValue(value, 0, false, 0);
}
/**
- * Creates a new {@link AutoFillValue} to auto-fill a toggable field.
+ * Creates a new {@link AutoFillValue} to auto-fill a {@link View} representing a toggable
+ * field.
*
* See {@link AutoFillType#isToggle()} for more info.
*/
public static AutoFillValue forToggle(boolean value) {
- return new AutoFillValue(null, 0, value);
+ return new AutoFillValue(null, 0, value, 0);
}
/**
- * Creates a new {@link AutoFillValue} to auto-fill a selection list field.
+ * Creates a new {@link AutoFillValue} to auto-fill a {@link View} representing a selection
+ * list.
*
* See {@link AutoFillType#isList()} for more info.
*/
public static AutoFillValue forList(int value) {
- return new AutoFillValue(null, value, false);
+ return new AutoFillValue(null, value, false, 0);
+ }
+
+ /**
+ * Creates a new {@link AutoFillValue} to auto-fill a {@link View} representing a date.
+ *
+ * See {@link AutoFillType#isDate()} for more info.
+ */
+ public static AutoFillValue forDate(long date) {
+ return new AutoFillValue(null, 0, false, date);
}
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 887c59a2d71cd..141b52fd2ce3f 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -591,7 +591,7 @@ public abstract class CompoundButton extends Button implements Checkable {
@Override
public AutoFillType getAutoFillType() {
- return AutoFillType.forToggle();
+ return isEnabled() ? AutoFillType.forToggle() : null;
}
@Override
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 517e20cd19473..0ffefd091b068 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -31,7 +31,11 @@ import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.View;
+import android.view.ViewStructure;
import android.view.accessibility.AccessibilityEvent;
+import android.view.autofill.AutoFillManager;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
import com.android.internal.R;
@@ -170,6 +174,13 @@ public class DatePicker extends FrameLayout {
if (firstDayOfWeek != 0) {
setFirstDayOfWeek(firstDayOfWeek);
}
+
+ mDelegate.setAutoFillChangeListener((v, y, m, d) -> {
+ final AutoFillManager afm = context.getSystemService(AutoFillManager.class);
+ if (afm != null) {
+ afm.valueChanged(this);
+ }
+ });
}
private DatePickerDelegate createSpinnerUIDelegate(Context context, AttributeSet attrs,
@@ -503,12 +514,15 @@ public class DatePicker extends FrameLayout {
OnDateChangedListener onDateChangedListener);
void setOnDateChangedListener(OnDateChangedListener onDateChangedListener);
+ 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 setFirstDayOfWeek(int firstDayOfWeek);
int getFirstDayOfWeek();
@@ -558,6 +572,7 @@ public class DatePicker extends FrameLayout {
// Callbacks
protected OnDateChangedListener mOnDateChangedListener;
+ protected OnDateChangedListener mAutoFillChangeListener;
protected ValidationCallback mValidationCallback;
public AbstractDatePickerDelegate(DatePicker delegator, Context context) {
@@ -579,11 +594,29 @@ public class DatePicker extends FrameLayout {
mOnDateChangedListener = callback;
}
+ @Override
+ public void setAutoFillChangeListener(OnDateChangedListener callback) {
+ mAutoFillChangeListener = callback;
+ }
+
@Override
public void setValidationCallback(ValidationCallback callback) {
mValidationCallback = callback;
}
+ @Override
+ public void updateDate(long date) {
+ Calendar cal = Calendar.getInstance(mCurrentLocale);
+ cal.setTimeInMillis(date);
+ updateDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
+ cal.get(Calendar.DAY_OF_MONTH));
+ }
+
+ @Override
+ public long getDate() {
+ return mCurrentDate.getTimeInMillis();
+ }
+
protected void onValidationChanged(boolean valid) {
if (mValidationCallback != null) {
mValidationCallback.onValidationChanged(valid);
@@ -723,4 +756,31 @@ public class DatePicker extends FrameLayout {
public interface ValidationCallback {
void onValidationChanged(boolean valid);
}
+
+ // TODO(b/33197203): add unit/CTS tests for auto-fill methods (and make sure they handle enable)
+
+ @Override
+ public void dispatchProvideAutoFillStructure(ViewStructure structure, int flags) {
+ // This view is self-sufficient for auto-fill, so it needs to call
+ // onProvideAutoFillStructure() to fill itself, but it does not need to call
+ // dispatchProvideAutoFillStructure() to fill its children.
+ onProvideAutoFillStructure(structure, flags);
+ }
+
+ @Override
+ public void autoFill(AutoFillValue value) {
+ if (!isEnabled()) return;
+
+ mDelegate.updateDate(value.getDateValue());
+ }
+
+ @Override
+ public AutoFillType getAutoFillType() {
+ return isEnabled() ? AutoFillType.forDate() : null;
+ }
+
+ @Override
+ public AutoFillValue getAutoFillValue() {
+ return isEnabled() ? AutoFillValue.forDate(mDelegate.getDate()) : null;
+ }
}
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 907250aa55982..ca1bf582e6036 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -390,10 +390,16 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate {
private void onDateChanged(boolean fromUser, boolean callbackToClient) {
final int year = mCurrentDate.get(Calendar.YEAR);
- if (callbackToClient && mOnDateChangedListener != null) {
+ if (callbackToClient
+ && (mOnDateChangedListener != null || mAutoFillChangeListener != null)) {
final int monthOfYear = mCurrentDate.get(Calendar.MONTH);
final int dayOfMonth = mCurrentDate.get(Calendar.DAY_OF_MONTH);
- mOnDateChangedListener.onDateChanged(mDelegator, year, monthOfYear, dayOfMonth);
+ if (mOnDateChangedListener != null) {
+ mOnDateChangedListener.onDateChanged(mDelegator, year, monthOfYear, dayOfMonth);
+ }
+ if (mAutoFillChangeListener != null) {
+ mAutoFillChangeListener.onDateChanged(mDelegator, year, monthOfYear, dayOfMonth);
+ }
}
mDayPickerView.setDate(mCurrentDate.getTimeInMillis());
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index 702b2a5f822a9..fc2d1faca019c 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -576,6 +576,10 @@ class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate {
mOnDateChangedListener.onDateChanged(mDelegator, getYear(), getMonth(),
getDayOfMonth());
}
+ if (mAutoFillChangeListener != null) {
+ mAutoFillChangeListener.onDateChanged(mDelegator, getYear(), getMonth(),
+ getDayOfMonth());
+ }
}
/**
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index bba3a11042e07..be5fc5381ac70 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -436,7 +436,7 @@ public class RadioGroup extends LinearLayout {
@Override
public AutoFillType getAutoFillType() {
- return AutoFillType.forList();
+ return isEnabled() ? AutoFillType.forList() : null;
}
@Override
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 9f38b04d4e099..1df202e96a3bf 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -23,12 +23,17 @@ import android.annotation.TestApi;
import android.annotation.Widget;
import android.content.Context;
import android.content.res.TypedArray;
+import android.icu.util.Calendar;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.MathUtils;
import android.view.View;
+import android.view.ViewStructure;
import android.view.accessibility.AccessibilityEvent;
+import android.view.autofill.AutoFillManager;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
import com.android.internal.R;
@@ -132,6 +137,12 @@ public class TimePicker extends FrameLayout {
this, context, attrs, defStyleAttr, defStyleRes);
break;
}
+ mDelegate.setAutoFillChangeListener((v, h, m) -> {
+ final AutoFillManager afm = context.getSystemService(AutoFillManager.class);
+ if (afm != null) {
+ afm.valueChanged(this);
+ }
+ });
}
/**
@@ -348,12 +359,16 @@ public class TimePicker extends FrameLayout {
void setMinute(@IntRange(from = 0, to = 59) int minute);
int getMinute();
+ void setDate(long date);
+ long getDate();
+
void setIs24Hour(boolean is24Hour);
boolean is24Hour();
boolean validateInput();
void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener);
+ void setAutoFillChangeListener(OnTimeChangedListener autoFillChangeListener);
void setEnabled(boolean enabled);
boolean isEnabled();
@@ -398,6 +413,7 @@ public class TimePicker extends FrameLayout {
protected final Locale mLocale;
protected OnTimeChangedListener mOnTimeChangedListener;
+ protected OnTimeChangedListener mAutoFillChangeListener;
public AbstractTimePickerDelegate(@NonNull TimePicker delegator, @NonNull Context context) {
mDelegator = delegator;
@@ -410,6 +426,27 @@ public class TimePicker extends FrameLayout {
mOnTimeChangedListener = callback;
}
+ @Override
+ public void setAutoFillChangeListener(OnTimeChangedListener callback) {
+ mAutoFillChangeListener = callback;
+ }
+
+ @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));
+ }
+
+ @Override
+ public long getDate() {
+ Calendar cal = Calendar.getInstance(mLocale);
+ cal.set(Calendar.HOUR_OF_DAY, getHour());
+ cal.set(Calendar.MINUTE, getMinute());
+ return cal.getTimeInMillis();
+ }
+
protected static class SavedState extends View.BaseSavedState {
private final int mHour;
private final int mMinute;
@@ -474,4 +511,31 @@ public class TimePicker extends FrameLayout {
};
}
}
+
+ // TODO(b/33197203): add unit/CTS tests for auto-fill methods (and make sure they handle enable)
+
+ @Override
+ public void dispatchProvideAutoFillStructure(ViewStructure structure, int flags) {
+ // This view is self-sufficient for auto-fill, so it needs to call
+ // onProvideAutoFillStructure() to fill itself, but it does not need to call
+ // dispatchProvideAutoFillStructure() to fill its children.
+ onProvideAutoFillStructure(structure, flags);
+ }
+
+ @Override
+ public void autoFill(AutoFillValue value) {
+ if (!isEnabled()) return;
+
+ mDelegate.setDate(value.getDateValue());
+ }
+
+ @Override
+ public AutoFillType getAutoFillType() {
+ return isEnabled() ? AutoFillType.forDate() : null;
+ }
+
+ @Override
+ public AutoFillValue getAutoFillValue() {
+ return isEnabled() ? AutoFillValue.forDate(mDelegate.getDate()) : null;
+ }
}
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 3a0906393b978..61ae7823bcf14 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -671,6 +671,9 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
if (mOnTimeChangedListener != null) {
mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute());
}
+ if (mAutoFillChangeListener != null) {
+ mAutoFillChangeListener.onTimeChanged(mDelegator, getHour(), getMinute());
+ }
}
private void tryVibrate() {
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 20a55129a19d3..813c30e344c05 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -495,6 +495,9 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate {
mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(),
getMinute());
}
+ if (mAutoFillChangeListener != null) {
+ mAutoFillChangeListener.onTimeChanged(mDelegator, getHour(), getMinute());
+ }
}
private void updateHourControl() {