diff options
5 files changed, 175 insertions, 14 deletions
diff --git a/api/current.txt b/api/current.txt index 3a35311a91e7..57b28152073e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -42611,6 +42611,7 @@ package android.service.autofill { public static final class FillResponse.Builder { ctor public FillResponse.Builder(); method @NonNull public android.service.autofill.FillResponse.Builder addDataset(@Nullable android.service.autofill.Dataset); + method @NonNull public android.service.autofill.FillResponse.Builder addInlineAction(@NonNull android.service.autofill.InlinePresentation); method @NonNull public android.service.autofill.FillResponse build(); method @NonNull public android.service.autofill.FillResponse.Builder disableAutofill(long); method @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.widget.RemoteViews); @@ -42640,10 +42641,11 @@ package android.service.autofill { } public final class InlinePresentation implements android.os.Parcelable { - ctor public InlinePresentation(@NonNull android.app.slice.Slice, @NonNull android.view.inline.InlinePresentationSpec); + ctor public InlinePresentation(@NonNull android.app.slice.Slice, @NonNull android.view.inline.InlinePresentationSpec, boolean); method public int describeContents(); method @NonNull public android.view.inline.InlinePresentationSpec getInlinePresentationSpec(); method @NonNull public android.app.slice.Slice getSlice(); + method public boolean isPinned(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.InlinePresentation> CREATOR; } @@ -55581,10 +55583,13 @@ package android.view.inputmethod { method @Nullable public String[] getAutofillHints(); method @NonNull public android.view.inline.InlinePresentationSpec getPresentationSpec(); method @NonNull public String getSource(); + method @NonNull public String getType(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.InlineSuggestionInfo> CREATOR; field public static final String SOURCE_AUTOFILL = "android:autofill"; field public static final String SOURCE_PLATFORM = "android:platform"; + field public static final String TYPE_ACTION = "android:autofill:action"; + field public static final String TYPE_SUGGESTION = "android:autofill:suggestion"; } public final class InlineSuggestionsRequest implements android.os.Parcelable { diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java index dc0f5623e5e3..9333dbd1e1d5 100644 --- a/core/java/android/service/autofill/FillResponse.java +++ b/core/java/android/service/autofill/FillResponse.java @@ -87,6 +87,7 @@ public final class FillResponse implements Parcelable { private final @Nullable UserData mUserData; private final @Nullable int[] mCancelIds; private final boolean mSupportsInlineSuggestions; + private final @Nullable ParceledListSlice<InlinePresentation> mInlineActions; private FillResponse(@NonNull Builder builder) { mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null; @@ -105,6 +106,8 @@ public final class FillResponse implements Parcelable { mUserData = builder.mUserData; mCancelIds = builder.mCancelIds; mSupportsInlineSuggestions = builder.mSupportsInlineSuggestions; + mInlineActions = (builder.mInlineActions != null) ? new ParceledListSlice<>( + builder.mInlineActions) : null; } /** @hide */ @@ -202,6 +205,11 @@ public final class FillResponse implements Parcelable { return mSupportsInlineSuggestions; } + /** @hide */ + public @Nullable List<InlinePresentation> getInlineActions() { + return (mInlineActions != null) ? mInlineActions.getList() : null; + } + /** * Builder for {@link FillResponse} objects. You must to provide at least * one dataset or set an authentication intent with a presentation view. @@ -223,6 +231,7 @@ public final class FillResponse implements Parcelable { private UserData mUserData; private int[] mCancelIds; private boolean mSupportsInlineSuggestions; + private ArrayList<InlinePresentation> mInlineActions; /** * Triggers a custom UI before before autofilling the screen with any data set in this @@ -578,6 +587,25 @@ public final class FillResponse implements Parcelable { } /** + * Adds a new {@link InlinePresentation} to this response representing an action UI. + * + * <p> For example, the UI can be associated with an intent which can open an activity for + * the user to manage the Autofill provider settings. + * + * @return This builder. + */ + @NonNull + public Builder addInlineAction(@NonNull InlinePresentation inlineAction) { + throwIfDestroyed(); + throwIfAuthenticationCalled(); + if (mInlineActions == null) { + mInlineActions = new ArrayList<>(); + } + mInlineActions.add(inlineAction); + return this; + } + + /** * Builds a new {@link FillResponse} instance. * * @throws IllegalStateException if any of the following conditions occur: @@ -688,6 +716,10 @@ public final class FillResponse implements Parcelable { if (mCancelIds != null) { builder.append(", mCancelIds=").append(mCancelIds.length); } + builder.append(", mSupportInlinePresentations=").append(mSupportsInlineSuggestions); + if (mInlineActions != null) { + builder.append(", mInlineActions=" + mInlineActions.getList()); + } return builder.append("]").toString(); } @@ -717,6 +749,7 @@ public final class FillResponse implements Parcelable { parcel.writeInt(mFlags); parcel.writeIntArray(mCancelIds); parcel.writeInt(mRequestId); + parcel.writeParcelable(mInlineActions, flags); } public static final @android.annotation.NonNull Parcelable.Creator<FillResponse> CREATOR = @@ -771,6 +804,15 @@ public final class FillResponse implements Parcelable { final int[] cancelIds = parcel.createIntArray(); builder.setPresentationCancelIds(cancelIds); + final ParceledListSlice<InlinePresentation> inlineActionsSlice = parcel.readParcelable( + null); + final List<InlinePresentation> inlineActions = + (inlineActionsSlice != null) ? inlineActionsSlice.getList() : null; + final int inlineActionsCount = (inlineActions != null) ? inlineActions.size() : 0; + for (int i = 0; i < inlineActionsCount; i++) { + builder.addInlineAction(inlineActions.get(i)); + } + final FillResponse response = builder.build(); response.setRequestId(parcel.readInt()); diff --git a/core/java/android/service/autofill/InlinePresentation.java b/core/java/android/service/autofill/InlinePresentation.java index 1568fb3af4c0..fb8406e99fa0 100644 --- a/core/java/android/service/autofill/InlinePresentation.java +++ b/core/java/android/service/autofill/InlinePresentation.java @@ -34,10 +34,22 @@ import com.android.internal.util.DataClass; genEqualsHashCode = true) public final class InlinePresentation implements Parcelable { + + /** + * Represents the UI content and the action for the inline suggestion. + */ private final @NonNull Slice mSlice; + /** + * Specifies the UI specification for the inline suggestion. + */ private final @NonNull InlinePresentationSpec mInlinePresentationSpec; + /** + * Indicates whether the UI should be pinned, hence non-scrollable, in the host. + */ + private final boolean mPinned; + // Code below generated by codegen v1.0.14. @@ -53,30 +65,56 @@ public final class InlinePresentation implements Parcelable { //@formatter:off + /** + * Creates a new InlinePresentation. + * + * @param slice + * Represents the UI content and the action for the inline suggestion. + * @param inlinePresentationSpec + * Specifies the UI specification for the inline suggestion. + * @param pinned + * Indicates whether the UI should be pinned, hence non-scrollable, in the host. + */ @DataClass.Generated.Member public InlinePresentation( @NonNull Slice slice, - @NonNull InlinePresentationSpec inlinePresentationSpec) { + @NonNull InlinePresentationSpec inlinePresentationSpec, + boolean pinned) { this.mSlice = slice; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mSlice); this.mInlinePresentationSpec = inlinePresentationSpec; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mInlinePresentationSpec); + this.mPinned = pinned; // onConstructed(); // You can define this method to get a callback } + /** + * Represents the UI content and the action for the inline suggestion. + */ @DataClass.Generated.Member public @NonNull Slice getSlice() { return mSlice; } + /** + * Specifies the UI specification for the inline suggestion. + */ @DataClass.Generated.Member public @NonNull InlinePresentationSpec getInlinePresentationSpec() { return mInlinePresentationSpec; } + /** + * Indicates whether the UI should be pinned, hence non-scrollable, in the host. + */ + @DataClass.Generated.Member + public boolean isPinned() { + return mPinned; + } + @Override @DataClass.Generated.Member public String toString() { @@ -85,7 +123,8 @@ public final class InlinePresentation implements Parcelable { return "InlinePresentation { " + "slice = " + mSlice + ", " + - "inlinePresentationSpec = " + mInlinePresentationSpec + + "inlinePresentationSpec = " + mInlinePresentationSpec + ", " + + "pinned = " + mPinned + " }"; } @@ -103,7 +142,8 @@ public final class InlinePresentation implements Parcelable { //noinspection PointlessBooleanExpression return true && java.util.Objects.equals(mSlice, that.mSlice) - && java.util.Objects.equals(mInlinePresentationSpec, that.mInlinePresentationSpec); + && java.util.Objects.equals(mInlinePresentationSpec, that.mInlinePresentationSpec) + && mPinned == that.mPinned; } @Override @@ -115,6 +155,7 @@ public final class InlinePresentation implements Parcelable { int _hash = 1; _hash = 31 * _hash + java.util.Objects.hashCode(mSlice); _hash = 31 * _hash + java.util.Objects.hashCode(mInlinePresentationSpec); + _hash = 31 * _hash + Boolean.hashCode(mPinned); return _hash; } @@ -124,6 +165,9 @@ public final class InlinePresentation implements Parcelable { // You can override field parcelling by defining methods like: // void parcelFieldName(Parcel dest, int flags) { ... } + byte flg = 0; + if (mPinned) flg |= 0x4; + dest.writeByte(flg); dest.writeTypedObject(mSlice, flags); dest.writeTypedObject(mInlinePresentationSpec, flags); } @@ -139,6 +183,8 @@ public final class InlinePresentation implements Parcelable { // You can override field unparcelling by defining methods like: // static FieldType unparcelFieldName(Parcel in) { ... } + byte flg = in.readByte(); + boolean pinned = (flg & 0x4) != 0; Slice slice = (Slice) in.readTypedObject(Slice.CREATOR); InlinePresentationSpec inlinePresentationSpec = (InlinePresentationSpec) in.readTypedObject(InlinePresentationSpec.CREATOR); @@ -148,6 +194,7 @@ public final class InlinePresentation implements Parcelable { this.mInlinePresentationSpec = inlinePresentationSpec; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mInlinePresentationSpec); + this.mPinned = pinned; // onConstructed(); // You can define this method to get a callback } @@ -167,10 +214,10 @@ public final class InlinePresentation implements Parcelable { }; @DataClass.Generated( - time = 1578081082387L, + time = 1579726472535L, codegenVersion = "1.0.14", sourceFile = "frameworks/base/core/java/android/service/autofill/InlinePresentation.java", - inputSignatures = "private final @android.annotation.NonNull android.app.slice.Slice mSlice\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mInlinePresentationSpec\nclass InlinePresentation extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)") + inputSignatures = "private final @android.annotation.NonNull android.app.slice.Slice mSlice\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final boolean mPinned\nclass InlinePresentation extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/view/inputmethod/InlineSuggestionInfo.java b/core/java/android/view/inputmethod/InlineSuggestionInfo.java index 195b63a8fc8e..703b64f8224f 100644 --- a/core/java/android/view/inputmethod/InlineSuggestionInfo.java +++ b/core/java/android/view/inputmethod/InlineSuggestionInfo.java @@ -18,6 +18,7 @@ package android.view.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.annotation.TestApi; import android.os.Parcelable; import android.view.inline.InlinePresentationSpec; @@ -45,6 +46,17 @@ public final class InlineSuggestionInfo implements Parcelable { */ public static final @Source String SOURCE_PLATFORM = "android:platform"; + /** + * UI type: the UI contains an Autofill suggestion that will autofill the fields when tapped. + */ + public static final @Type String TYPE_SUGGESTION = "android:autofill:suggestion"; + + /** + * UI type: the UI contains an widget that will launch an intent when tapped. + */ + @SuppressLint({"IntentName"}) + public static final @Type String TYPE_ACTION = "android:autofill:action"; + /** The presentation spec to which the inflated suggestion view abides. */ private final @NonNull InlinePresentationSpec mPresentationSpec; @@ -54,6 +66,9 @@ public final class InlineSuggestionInfo implements Parcelable { /** Hints for the type of data being suggested. */ private final @Nullable String[] mAutofillHints; + /** The type of the UI. */ + private final @NonNull @Type String mType; + /** * Creates a new {@link InlineSuggestionInfo}, for testing purpose. * @@ -65,7 +80,8 @@ public final class InlineSuggestionInfo implements Parcelable { @NonNull InlinePresentationSpec presentationSpec, @NonNull @Source String source, @Nullable String[] autofillHints) { - return new InlineSuggestionInfo(presentationSpec, source, autofillHints); + // TODO(b/147394280): Add CTS test for the type field. + return new InlineSuggestionInfo(presentationSpec, source, autofillHints, TYPE_SUGGESTION); } @@ -92,6 +108,15 @@ public final class InlineSuggestionInfo implements Parcelable { @DataClass.Generated.Member public @interface Source {} + /** @hide */ + @android.annotation.StringDef(prefix = "TYPE_", value = { + TYPE_SUGGESTION, + TYPE_ACTION + }) + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) + @DataClass.Generated.Member + public @interface Type {} + /** * Creates a new InlineSuggestionInfo. * @@ -101,13 +126,16 @@ public final class InlineSuggestionInfo implements Parcelable { * The source from which the suggestion is provided. * @param autofillHints * Hints for the type of data being suggested. + * @param type + * The type of the UI. * @hide */ @DataClass.Generated.Member public InlineSuggestionInfo( @NonNull InlinePresentationSpec presentationSpec, @NonNull @Source String source, - @Nullable String[] autofillHints) { + @Nullable String[] autofillHints, + @NonNull @Type String type) { this.mPresentationSpec = presentationSpec; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mPresentationSpec); @@ -124,6 +152,18 @@ public final class InlineSuggestionInfo implements Parcelable { com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mSource); this.mAutofillHints = autofillHints; + this.mType = type; + + if (!(java.util.Objects.equals(mType, TYPE_SUGGESTION)) + && !(java.util.Objects.equals(mType, TYPE_ACTION))) { + throw new java.lang.IllegalArgumentException( + "type was " + mType + " but must be one of: " + + "TYPE_SUGGESTION(" + TYPE_SUGGESTION + "), " + + "TYPE_ACTION(" + TYPE_ACTION + ")"); + } + + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mType); // onConstructed(); // You can define this method to get a callback } @@ -152,6 +192,14 @@ public final class InlineSuggestionInfo implements Parcelable { return mAutofillHints; } + /** + * The type of the UI. + */ + @DataClass.Generated.Member + public @NonNull @Type String getType() { + return mType; + } + @Override @DataClass.Generated.Member public String toString() { @@ -161,7 +209,8 @@ public final class InlineSuggestionInfo implements Parcelable { return "InlineSuggestionInfo { " + "presentationSpec = " + mPresentationSpec + ", " + "source = " + mSource + ", " + - "autofillHints = " + java.util.Arrays.toString(mAutofillHints) + + "autofillHints = " + java.util.Arrays.toString(mAutofillHints) + ", " + + "type = " + mType + " }"; } @@ -180,7 +229,8 @@ public final class InlineSuggestionInfo implements Parcelable { return true && java.util.Objects.equals(mPresentationSpec, that.mPresentationSpec) && java.util.Objects.equals(mSource, that.mSource) - && java.util.Arrays.equals(mAutofillHints, that.mAutofillHints); + && java.util.Arrays.equals(mAutofillHints, that.mAutofillHints) + && java.util.Objects.equals(mType, that.mType); } @Override @@ -193,6 +243,7 @@ public final class InlineSuggestionInfo implements Parcelable { _hash = 31 * _hash + java.util.Objects.hashCode(mPresentationSpec); _hash = 31 * _hash + java.util.Objects.hashCode(mSource); _hash = 31 * _hash + java.util.Arrays.hashCode(mAutofillHints); + _hash = 31 * _hash + java.util.Objects.hashCode(mType); return _hash; } @@ -208,6 +259,7 @@ public final class InlineSuggestionInfo implements Parcelable { dest.writeTypedObject(mPresentationSpec, flags); dest.writeString(mSource); if (mAutofillHints != null) dest.writeStringArray(mAutofillHints); + dest.writeString(mType); } @Override @@ -225,6 +277,7 @@ public final class InlineSuggestionInfo implements Parcelable { InlinePresentationSpec presentationSpec = (InlinePresentationSpec) in.readTypedObject(InlinePresentationSpec.CREATOR); String source = in.readString(); String[] autofillHints = (flg & 0x4) == 0 ? null : in.createStringArray(); + String type = in.readString(); this.mPresentationSpec = presentationSpec; com.android.internal.util.AnnotationValidations.validate( @@ -242,6 +295,18 @@ public final class InlineSuggestionInfo implements Parcelable { com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mSource); this.mAutofillHints = autofillHints; + this.mType = type; + + if (!(java.util.Objects.equals(mType, TYPE_SUGGESTION)) + && !(java.util.Objects.equals(mType, TYPE_ACTION))) { + throw new java.lang.IllegalArgumentException( + "type was " + mType + " but must be one of: " + + "TYPE_SUGGESTION(" + TYPE_SUGGESTION + "), " + + "TYPE_ACTION(" + TYPE_ACTION + ")"); + } + + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mType); // onConstructed(); // You can define this method to get a callback } @@ -261,10 +326,10 @@ public final class InlineSuggestionInfo implements Parcelable { }; @DataClass.Generated( - time = 1578972121865L, + time = 1579806757327L, codegenVersion = "1.0.14", sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionInfo.java", - inputSignatures = "public static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_AUTOFILL\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_PLATFORM\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mPresentationSpec\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String mSource\nprivate final @android.annotation.Nullable java.lang.String[] mAutofillHints\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(android.view.inline.InlinePresentationSpec,java.lang.String,java.lang.String[])\nclass InlineSuggestionInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)") + inputSignatures = "public static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_AUTOFILL\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_PLATFORM\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_SUGGESTION\npublic static final @android.annotation.SuppressLint({\"IntentName\"}) @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_ACTION\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mPresentationSpec\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String mSource\nprivate final @android.annotation.Nullable java.lang.String[] mAutofillHints\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String mType\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(android.view.inline.InlinePresentationSpec,java.lang.String,java.lang.String[])\nclass InlineSuggestionInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)") @Deprecated private void __metadata() {} diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java index 5e6f97e4f282..fcbd088f7597 100644 --- a/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java +++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java @@ -123,7 +123,8 @@ public final class InlineSuggestionFactory { // TODO(b/146453195): fill in the autofill hint properly. final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo( inlinePresentation.getInlinePresentationSpec(), - InlineSuggestionInfo.SOURCE_PLATFORM, new String[]{""}); + InlineSuggestionInfo.SOURCE_PLATFORM, new String[]{""}, + InlineSuggestionInfo.TYPE_SUGGESTION); final View.OnClickListener onClickListener = v -> { try { client.autofill(sessionId, dataset.getFieldIds(), dataset.getFieldValues()); @@ -146,7 +147,8 @@ public final class InlineSuggestionFactory { // TODO(b/146453195): fill in the autofill hint properly. final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo( inlinePresentation.getInlinePresentationSpec(), - InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""}); + InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""}, + InlineSuggestionInfo.TYPE_SUGGESTION); final View.OnClickListener onClickListener = v -> { client.fill(requestId, fieldIndex, dataset); }; |