Merge "Add Autofill PCC Detection APIs for Autofill Providers"
diff --git a/core/api/current.txt b/core/api/current.txt
index 381b387..33af0ea 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -39475,6 +39475,7 @@
method @NonNull public android.service.autofill.Dataset build();
method @NonNull public android.service.autofill.Dataset.Builder setAuthentication(@Nullable android.content.IntentSender);
method @NonNull public android.service.autofill.Dataset.Builder setField(@NonNull android.view.autofill.AutofillId, @Nullable android.service.autofill.Field);
+ method @NonNull public android.service.autofill.Dataset.Builder setField(@NonNull String, @NonNull android.service.autofill.Field);
method @NonNull public android.service.autofill.Dataset.Builder setId(@Nullable String);
method @Deprecated @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.service.autofill.InlinePresentation);
method @Deprecated @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.service.autofill.InlinePresentation, @NonNull android.service.autofill.InlinePresentation);
@@ -39583,6 +39584,7 @@
method @Nullable public android.content.IntentSender getDelayedFillIntentSender();
method @NonNull public java.util.List<android.service.autofill.FillContext> getFillContexts();
method public int getFlags();
+ method @NonNull public java.util.List<java.lang.String> getHints();
method public int getId();
method @Nullable public android.view.inputmethod.InlineSuggestionsRequest getInlineSuggestionsRequest();
method public void writeToParcel(@NonNull android.os.Parcel, int);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 85861c3..908d167 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2529,6 +2529,7 @@
public final class Dataset implements android.os.Parcelable {
method @Nullable public android.content.IntentSender getAuthentication();
+ method @Nullable public java.util.ArrayList<java.lang.String> getAutofillDatatypes();
method @Nullable public android.content.ClipData getFieldContent();
method @Nullable public java.util.ArrayList<android.view.autofill.AutofillId> getFieldIds();
method @Nullable public java.util.ArrayList<android.view.autofill.AutofillValue> getFieldValues();
@@ -3278,6 +3279,7 @@
field public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_IGNORE_VIEWS = "autofill_credential_manager_ignore_views";
field public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED = "autofill_dialog_enabled";
field public static final String DEVICE_CONFIG_AUTOFILL_PCC_CLASSIFICATION_ENABLED = "pcc_classification_enabled";
+ field public static final String DEVICE_CONFIG_AUTOFILL_PCC_FEATURE_PROVIDER_HINTS = "pcc_classification_hints";
field public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = "smart_suggestion_supported_modes";
field public static final String DEVICE_CONFIG_NON_AUTOFILLABLE_IME_ACTION_IDS = "non_autofillable_ime_action_ids";
field public static final String DEVICE_CONFIG_PACKAGE_DENYLIST_FOR_UNIMPORTANT_VIEW = "package_deny_list_for_unimportant_view";
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index e9f099a..0fa5e3e 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -120,6 +120,8 @@
private final ArrayList<InlinePresentation> mFieldInlinePresentations;
private final ArrayList<InlinePresentation> mFieldInlineTooltipPresentations;
private final ArrayList<DatasetFieldFilter> mFieldFilters;
+ private final ArrayList<String> mAutofillDatatypes;
+
@Nullable private final ClipData mFieldContent;
private final RemoteViews mPresentation;
private final RemoteViews mDialogPresentation;
@@ -143,6 +145,14 @@
mInlineTooltipPresentation = builder.mInlineTooltipPresentation;
mAuthentication = builder.mAuthentication;
mId = builder.mId;
+ mAutofillDatatypes = builder.mAutofillDatatypes;
+ }
+
+ /** @hide */
+ @TestApi
+ @SuppressLint({"ConcreteCollection", "NullableCollection"})
+ public @Nullable ArrayList<String> getAutofillDatatypes() {
+ return mAutofillDatatypes;
}
/** @hide */
@@ -293,6 +303,7 @@
private ArrayList<InlinePresentation> mFieldInlinePresentations;
private ArrayList<InlinePresentation> mFieldInlineTooltipPresentations;
private ArrayList<DatasetFieldFilter> mFieldFilters;
+ private ArrayList<String> mAutofillDatatypes;
@Nullable private ClipData mFieldContent;
private RemoteViews mPresentation;
private RemoteViews mDialogPresentation;
@@ -922,6 +933,55 @@
}
/**
+ * Adds a field to this Dataset with a specific type and no
+ * AutofillId. This is used to send back Field information
+ * when Autofilling with platform detections is on.
+ * Platform detections are on when receiving a populated list from
+ * FillRequest#getHints().
+ *
+ * Populate every field/type known for this user for this app.
+ *
+ * For example, if getHints() contains "username" and "password",
+ * a new Dataset should be created that calls this method twice,
+ * one for the username, then another for the password (assuming
+ * the only one credential pair is found for the user). If a user
+ * has two credential pairs, then two Datasets should be created,
+ * and so on.
+ *
+ * Using this will remove any data populated with
+ * setField(@NonNull AutofillId id, @Nullable Field field).
+ *
+ * @param hint An autofill hint returned from {@link
+ * FillRequest#getHints()}.
+ *
+ * @param field the fill information about the field.
+ *
+ * @throws IllegalStateException if {@link #build()} was already called
+ * or this builder also contains AutofillId information
+ *
+ * @return this builder.
+ */
+ public @NonNull Dataset.Builder setField(
+ @NonNull String hint, @NonNull Field field) {
+ throwIfDestroyed();
+
+ final DatasetFieldFilter filter = field.getDatasetFieldFilter();
+ final Presentations presentations = field.getPresentations();
+ if (presentations == null) {
+ setLifeTheUniverseAndEverything(hint, field.getValue(), null, null, null,
+ filter, null);
+ } else {
+ setLifeTheUniverseAndEverything(hint, field.getValue(),
+ presentations.getMenuPresentation(),
+ presentations.getInlinePresentation(),
+ presentations.getInlineTooltipPresentation(), filter,
+ presentations.getDialogPresentation());
+ }
+
+ return this;
+ }
+
+ /**
* Sets the value of a field with an <a href="#Filtering">explicit filter</a>, and using an
* {@link InlinePresentation} to visualize it as an inline suggestion.
*
@@ -958,6 +1018,32 @@
return this;
}
+ private void setLifeTheUniverseAndEverything(String datatype,
+ @Nullable AutofillValue value,
+ @Nullable RemoteViews presentation,
+ @Nullable InlinePresentation inlinePresentation,
+ @Nullable InlinePresentation tooltip,
+ @Nullable DatasetFieldFilter filter,
+ @Nullable RemoteViews dialogPresentation) {
+ if (mAutofillDatatypes == null) {
+ mFieldValues = new ArrayList<>();
+ mFieldPresentations = new ArrayList<>();
+ mFieldDialogPresentations = new ArrayList<>();
+ mFieldInlinePresentations = new ArrayList<>();
+ mFieldInlineTooltipPresentations = new ArrayList<>();
+ mFieldFilters = new ArrayList<>();
+ mAutofillDatatypes = new ArrayList<>();
+ mFieldIds = null;
+ }
+ mFieldValues.add(value);
+ mFieldPresentations.add(presentation);
+ mFieldDialogPresentations.add(dialogPresentation);
+ mFieldInlinePresentations.add(inlinePresentation);
+ mFieldInlineTooltipPresentations.add(tooltip);
+ mFieldFilters.add(filter);
+ mAutofillDatatypes.add(datatype);
+ }
+
private void setLifeTheUniverseAndEverything(@NonNull AutofillId id,
@Nullable AutofillValue value, @Nullable RemoteViews presentation,
@Nullable InlinePresentation inlinePresentation,
@@ -984,6 +1070,7 @@
mFieldInlinePresentations = new ArrayList<>();
mFieldInlineTooltipPresentations = new ArrayList<>();
mFieldFilters = new ArrayList<>();
+ mAutofillDatatypes = null;
}
mFieldIds.add(id);
mFieldValues.add(value);
@@ -1007,9 +1094,14 @@
public @NonNull Dataset build() {
throwIfDestroyed();
mDestroyed = true;
- if (mFieldIds == null) {
+ if (mFieldIds == null && mAutofillDatatypes == null) {
throw new IllegalStateException("at least one value must be set");
}
+ if (mFieldIds != null && mAutofillDatatypes != null) {
+ if (mFieldIds.size() > 0 && mAutofillDatatypes.size() > 0) {
+ throw new IllegalStateException("both field and datatype were populated");
+ }
+ }
if (mFieldContent != null) {
if (mFieldIds.size() > 1) {
throw new IllegalStateException(
@@ -1051,6 +1143,7 @@
parcel.writeTypedList(mFieldInlinePresentations, flags);
parcel.writeTypedList(mFieldInlineTooltipPresentations, flags);
parcel.writeTypedList(mFieldFilters, flags);
+ parcel.writeStringList(mAutofillDatatypes);
parcel.writeParcelable(mFieldContent, flags);
parcel.writeParcelable(mAuthentication, flags);
parcel.writeString(mId);
@@ -1081,6 +1174,8 @@
parcel.createTypedArrayList(InlinePresentation.CREATOR);
final ArrayList<DatasetFieldFilter> filters =
parcel.createTypedArrayList(DatasetFieldFilter.CREATOR);
+ final ArrayList<String> datatypes =
+ parcel.createStringArrayList();
final ClipData fieldContent = parcel.readParcelable(null,
android.content.ClipData.class);
final IntentSender authentication = parcel.readParcelable(null,
@@ -1114,19 +1209,37 @@
builder.setContent(ids.get(0), fieldContent);
}
final int inlinePresentationsSize = inlinePresentations.size();
- for (int i = 0; i < ids.size(); i++) {
- final AutofillId id = ids.get(i);
- final AutofillValue value = values.get(i);
- final RemoteViews fieldPresentation = presentations.get(i);
- final RemoteViews fieldDialogPresentation = dialogPresentations.get(i);
- final InlinePresentation fieldInlinePresentation =
- i < inlinePresentationsSize ? inlinePresentations.get(i) : null;
- final InlinePresentation fieldInlineTooltipPresentation =
- i < inlinePresentationsSize ? inlineTooltipPresentations.get(i) : null;
- final DatasetFieldFilter filter = filters.get(i);
- builder.setLifeTheUniverseAndEverything(id, value, fieldPresentation,
- fieldInlinePresentation, fieldInlineTooltipPresentation, filter,
- fieldDialogPresentation);
+
+ if (ids.size() == 0 && datatypes.size() > 0) {
+ for (int i = 0; i < ids.size(); i++) {
+ final String datatype = datatypes.get(i);
+ final AutofillValue value = values.get(i);
+ final RemoteViews fieldPresentation = presentations.get(i);
+ final RemoteViews fieldDialogPresentation = dialogPresentations.get(i);
+ final InlinePresentation fieldInlinePresentation =
+ i < inlinePresentationsSize ? inlinePresentations.get(i) : null;
+ final InlinePresentation fieldInlineTooltipPresentation =
+ i < inlinePresentationsSize ? inlineTooltipPresentations.get(i) : null;
+ final DatasetFieldFilter filter = filters.get(i);
+ builder.setLifeTheUniverseAndEverything(
+ datatype, value, fieldPresentation, fieldInlinePresentation,
+ fieldInlineTooltipPresentation, filter, fieldDialogPresentation);
+ }
+ } else {
+ for (int i = 0; i < ids.size(); i++) {
+ final AutofillId id = ids.get(i);
+ final AutofillValue value = values.get(i);
+ final RemoteViews fieldPresentation = presentations.get(i);
+ final RemoteViews fieldDialogPresentation = dialogPresentations.get(i);
+ final InlinePresentation fieldInlinePresentation =
+ i < inlinePresentationsSize ? inlinePresentations.get(i) : null;
+ final InlinePresentation fieldInlineTooltipPresentation =
+ i < inlinePresentationsSize ? inlineTooltipPresentations.get(i) : null;
+ final DatasetFieldFilter filter = filters.get(i);
+ builder.setLifeTheUniverseAndEverything(id, value, fieldPresentation,
+ fieldInlinePresentation, fieldInlineTooltipPresentation, filter,
+ fieldDialogPresentation);
+ }
}
builder.setAuthentication(authentication);
builder.setId(datasetId);
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index eb5e893..4a848dd 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -141,6 +141,19 @@
private final @NonNull List<FillContext> mFillContexts;
/**
+ * Sends a list of datatypes for the Autofill Provider.
+ *
+ * If this is populated, Autofill Provider should return data
+ * for the autofill hints requested here,
+ * even though the Autofill Provider may not have detected these types.
+ * The hints would be part of HintConstants:
+ * https://developer.android.com/reference/androidx/autofill/HintConstants
+ *
+ * This is populated if the platform's field detection is enabled.
+ */
+ private final @NonNull List<String> mHints;
+
+ /**
* Gets the latest client state bundle set by the service in a
* {@link FillResponse.Builder#setClientState(Bundle) fill response}.
*
@@ -196,6 +209,7 @@
private void onConstructed() {
Preconditions.checkCollectionElementsNotNull(mFillContexts, "contexts");
+ Preconditions.checkCollectionElementsNotNull(mHints, "hints");
}
@@ -269,6 +283,11 @@
* <p><b>Note:</b> Starting on Android {@link android.os.Build.VERSION_CODES#Q}, it could also
* include contexts from requests whose {@link SaveInfo} had the
* {@link SaveInfo#FLAG_DELAY_SAVE} flag.
+ * @param hints
+ * Autofill Provider should return data for the autofill hints requested here,
+ * even though the Autofill Provider may not have detected these types.
+ * The hints would be part of HintConstants:
+ * https://developer.android.com/reference/androidx/autofill/HintConstants
* @param clientState
* Gets the latest client state bundle set by the service in a
* {@link FillResponse.Builder#setClientState(Bundle) fill response}.
@@ -312,6 +331,7 @@
public FillRequest(
int id,
@NonNull List<FillContext> fillContexts,
+ @NonNull List<String> hints,
@Nullable Bundle clientState,
@RequestFlags int flags,
@Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
@@ -320,6 +340,9 @@
this.mFillContexts = fillContexts;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mFillContexts);
+ this.mHints = hints;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mHints);
this.mClientState = clientState;
this.mFlags = flags;
@@ -360,6 +383,17 @@
}
/**
+ * Autofill Provider should return data for the autofill hints requested here,
+ * even though the Autofill Provider may not have detected these types.
+ * The hints would be part of HintConstants:
+ * https://developer.android.com/reference/androidx/autofill/HintConstants
+ */
+ @DataClass.Generated.Member
+ public @NonNull List<String> getHints() {
+ return mHints;
+ }
+
+ /**
* Gets the latest client state bundle set by the service in a
* {@link FillResponse.Builder#setClientState(Bundle) fill response}.
*
@@ -433,6 +467,7 @@
return "FillRequest { " +
"id = " + mId + ", " +
"fillContexts = " + mFillContexts + ", " +
+ "hints = " + mHints + ", " +
"clientState = " + mClientState + ", " +
"flags = " + requestFlagsToString(mFlags) + ", " +
"inlineSuggestionsRequest = " + mInlineSuggestionsRequest + ", " +
@@ -447,12 +482,13 @@
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
- if (mClientState != null) flg |= 0x4;
- if (mInlineSuggestionsRequest != null) flg |= 0x10;
- if (mDelayedFillIntentSender != null) flg |= 0x20;
+ if (mClientState != null) flg |= 0x8;
+ if (mInlineSuggestionsRequest != null) flg |= 0x20;
+ if (mDelayedFillIntentSender != null) flg |= 0x40;
dest.writeByte(flg);
dest.writeInt(mId);
dest.writeParcelableList(mFillContexts, flags);
+ dest.writeStringList(mHints);
if (mClientState != null) dest.writeBundle(mClientState);
dest.writeInt(mFlags);
if (mInlineSuggestionsRequest != null) dest.writeTypedObject(mInlineSuggestionsRequest, flags);
@@ -474,15 +510,20 @@
int id = in.readInt();
List<FillContext> fillContexts = new ArrayList<>();
in.readParcelableList(fillContexts, FillContext.class.getClassLoader());
- Bundle clientState = (flg & 0x4) == 0 ? null : in.readBundle();
+ List<String> hints = new ArrayList<>();
+ in.readStringList(hints);
+ Bundle clientState = (flg & 0x8) == 0 ? null : in.readBundle();
int flags = in.readInt();
- InlineSuggestionsRequest inlineSuggestionsRequest = (flg & 0x10) == 0 ? null : (InlineSuggestionsRequest) in.readTypedObject(InlineSuggestionsRequest.CREATOR);
- IntentSender delayedFillIntentSender = (flg & 0x20) == 0 ? null : (IntentSender) in.readTypedObject(IntentSender.CREATOR);
+ InlineSuggestionsRequest inlineSuggestionsRequest = (flg & 0x20) == 0 ? null : (InlineSuggestionsRequest) in.readTypedObject(InlineSuggestionsRequest.CREATOR);
+ IntentSender delayedFillIntentSender = (flg & 0x40) == 0 ? null : (IntentSender) in.readTypedObject(IntentSender.CREATOR);
this.mId = id;
this.mFillContexts = fillContexts;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mFillContexts);
+ this.mHints = hints;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mHints);
this.mClientState = clientState;
this.mFlags = flags;
@@ -517,10 +558,10 @@
};
@DataClass.Generated(
- time = 1675460688829L,
+ time = 1675711417112L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
- inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_RESET_FILL_DIALOG_STATE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PCC_DETECTION\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_RESET_FILL_DIALOG_STATE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PCC_DETECTION\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mHints\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 5fe1d4f..828e466 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -308,7 +308,7 @@
* username field, another for password).
*/
// TODO(b/113281366): improve documentation: add example, document relationship with other
- // flagss, etc...
+ // flags, etc...
public static final int FLAG_DELAY_SAVE = 0x4;
/** @hide */
@@ -777,17 +777,13 @@
/**
* Builds a new {@link SaveInfo} instance.
*
- * @throws IllegalStateException if no
- * {@link #Builder(int, AutofillId[]) required ids},
+ * If no {@link #Builder(int, AutofillId[]) required ids},
* or {@link #setOptionalIds(AutofillId[]) optional ids}, or {@link #FLAG_DELAY_SAVE}
- * were set
+ * were set, Save Dialog will only be triggered if platform detection is enabled, which
+ * is indicated when {@link FillRequest.getHints()} is not empty.
*/
public SaveInfo build() {
throwIfDestroyed();
- Preconditions.checkState(
- !ArrayUtils.isEmpty(mRequiredIds) || !ArrayUtils.isEmpty(mOptionalIds)
- || (mFlags & FLAG_DELAY_SAVE) != 0,
- "must have at least one required or optional id or FLAG_DELAYED_SAVE");
mDestroyed = true;
return new SaveInfo(this);
}
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index e7c610b..f3a8e85 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -82,6 +82,12 @@
"autofill_dialog_enabled";
/**
+ * Indicates that PCC Autofill detection feature is enabled or not.
+ */
+ public static final String DEVICE_CONFIG_AUTOFILL_PCC_FEATURE_PROVIDER_HINTS =
+ "pcc_classification_hints";
+
+ /**
* Sets the autofill hints allowed list for the fields that can trigger the fill dialog
* feature at Activity starting.
*
@@ -190,9 +196,11 @@
"autofill_inline_tooltip_first_show_delay";
private static final String DIALOG_HINTS_DELIMITER = ":";
+ private static final String PCC_HINTS_DELIMITER = ",";
private static final boolean DEFAULT_HAS_FILL_DIALOG_UI_FEATURE = false;
private static final String DEFAULT_FILL_DIALOG_ENABLED_HINTS = "";
+ private static final String DEFAULT_PCC_FEATURE_PROVIDER_HINTS = "";
// CREDENTIAL MANAGER DEFAULTS
@@ -225,6 +233,25 @@
}
/**
+ * The list of datatypes that is supported by framework
+ * detection.
+ *
+ * @hide
+ */
+ public static String[] getTypeHintsForProvider() {
+ final String typeHints = DeviceConfig.getString(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ DEVICE_CONFIG_AUTOFILL_PCC_FEATURE_PROVIDER_HINTS,
+ DEFAULT_PCC_FEATURE_PROVIDER_HINTS);
+ if (TextUtils.isEmpty(typeHints)) {
+ return new String[0];
+ }
+
+ return ArrayUtils.filter(typeHints.split(PCC_HINTS_DELIMITER), String[]::new,
+ (str) -> !TextUtils.isEmpty(str));
+ }
+
+ /**
* Gets fill dialog enabled hints.
*
* @hide
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 2b529bf..a23a58d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -117,6 +117,7 @@
import android.util.SparseArray;
import android.util.TimeUtils;
import android.view.KeyEvent;
+import android.view.autofill.AutofillFeatureFlags;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillManager.AutofillCommitReason;
@@ -146,6 +147,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -564,6 +566,7 @@
if (mPendingInlineSuggestionsRequest.isServiceSupported()) {
mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
mPendingFillRequest.getFillContexts(),
+ mPendingFillRequest.getHints(),
mPendingFillRequest.getClientState(),
mPendingFillRequest.getFlags(),
mPendingInlineSuggestionsRequest,
@@ -672,8 +675,10 @@
final ArrayList<FillContext> contexts =
mergePreviousSessionLocked(/* forSave= */ false);
+ final List<String> hints = getTypeHintsForProvider();
+
mDelayedFillPendingIntent = createPendingIntent(requestId);
- request = new FillRequest(requestId, contexts, mClientState, flags,
+ request = new FillRequest(requestId, contexts, hints, mClientState, flags,
/*inlineSuggestionsRequest=*/ null,
/*delayedFillIntentSender=*/ mDelayedFillPendingIntent == null
? null
@@ -705,6 +710,19 @@
}
/**
+ * Get the list of valid autofill hint types from Device flags
+ * Returns empty list if PCC is off or no types available
+ */
+ private List<String> getTypeHintsForProvider() {
+ if (!AutofillFeatureFlags.isAutofillPccClassificationEnabled()) {
+ return Collections.EMPTY_LIST;
+ }
+
+ String[] typeHints = AutofillFeatureFlags.getTypeHintsForProvider();
+ return List.copyOf(Set.of(typeHints));
+ }
+
+ /**
* Assist Data Receiver for PCC
*/
private final class PccAssistDataReceiverImpl extends IAssistDataReceiver.Stub {