Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2901b78a authored by TYM Tsai's avatar TYM Tsai
Browse files

Add interface for the inline suggestion tooltip

The inline suggestion tooltip is used to show some descriptions for a
specific inline suggestion to let the user easily understand the
suggestion and promo the suggestion. Or educates the user how to
operate the inline strip.

The patch defines some APIs to enable the suggestion provider to
conveniently provide tooltips for the user.

Bug: 172024354
Test: atest CtsAutoFillServiceTestCases:InlineTooltipTest
Change-Id: I5b0fc481b7352da2804f0e4f4633f1698a69109b
parent 36ce6961
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -37387,12 +37387,15 @@ package android.service.autofill {
    method @NonNull public android.service.autofill.Dataset.Builder setAuthentication(@Nullable android.content.IntentSender);
    method @NonNull public android.service.autofill.Dataset.Builder setId(@Nullable String);
    method @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.service.autofill.InlinePresentation);
    method @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.service.autofill.InlinePresentation, @NonNull android.service.autofill.InlinePresentation);
    method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue);
    method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @NonNull android.widget.RemoteViews);
    method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern);
    method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.widget.RemoteViews);
    method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @NonNull android.widget.RemoteViews, @NonNull android.service.autofill.InlinePresentation);
    method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @NonNull android.widget.RemoteViews, @NonNull android.service.autofill.InlinePresentation, @NonNull android.service.autofill.InlinePresentation);
    method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.widget.RemoteViews, @NonNull android.service.autofill.InlinePresentation);
    method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.widget.RemoteViews, @NonNull android.service.autofill.InlinePresentation, @NonNull android.service.autofill.InlinePresentation);
  }
  public final class DateTransformation implements android.os.Parcelable android.service.autofill.Transformation {
@@ -37493,6 +37496,7 @@ package android.service.autofill {
    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);
    method @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.widget.RemoteViews, @Nullable android.service.autofill.InlinePresentation);
    method @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.widget.RemoteViews, @Nullable android.service.autofill.InlinePresentation, @Nullable android.service.autofill.InlinePresentation);
    method @NonNull public android.service.autofill.FillResponse.Builder setClientState(@Nullable android.os.Bundle);
    method @NonNull public android.service.autofill.FillResponse.Builder setFieldClassificationIds(@NonNull android.view.autofill.AutofillId...);
    method @NonNull public android.service.autofill.FillResponse.Builder setFlags(int);
@@ -37520,6 +37524,7 @@ package android.service.autofill {
  public final class InlinePresentation implements android.os.Parcelable {
    ctor public InlinePresentation(@NonNull android.app.slice.Slice, @NonNull android.widget.inline.InlinePresentationSpec, boolean);
    method @NonNull public static android.service.autofill.InlinePresentation createTooltipPresentation(@NonNull android.app.slice.Slice, @NonNull android.widget.inline.InlinePresentationSpec);
    method public int describeContents();
    method @NonNull public android.widget.inline.InlinePresentationSpec getInlinePresentationSpec();
    method @NonNull public android.app.slice.Slice getSlice();
@@ -51327,6 +51332,7 @@ package android.view.inputmethod {
    method @NonNull public android.os.Bundle getExtras();
    method @NonNull public String getHostPackageName();
    method @NonNull public java.util.List<android.widget.inline.InlinePresentationSpec> getInlinePresentationSpecs();
    method @Nullable public android.widget.inline.InlinePresentationSpec getInlineTooltipPresentationSpec();
    method public int getMaxSuggestionCount();
    method @NonNull public android.os.LocaleList getSupportedLocales();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -51338,9 +51344,12 @@ package android.view.inputmethod {
    ctor public InlineSuggestionsRequest.Builder(@NonNull java.util.List<android.widget.inline.InlinePresentationSpec>);
    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder addInlinePresentationSpecs(@NonNull android.widget.inline.InlinePresentationSpec);
    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest build();
    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setClientSupported(boolean);
    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setExtras(@NonNull android.os.Bundle);
    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(@NonNull java.util.List<android.widget.inline.InlinePresentationSpec>);
    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setInlineTooltipPresentationSpec(@NonNull android.widget.inline.InlinePresentationSpec);
    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setMaxSuggestionCount(int);
    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setServiceSupported(boolean);
    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setSupportedLocales(@NonNull android.os.LocaleList);
  }
+149 −2
Original line number Diff line number Diff line
@@ -107,10 +107,12 @@ public final class Dataset implements Parcelable {
    private final ArrayList<AutofillValue> mFieldValues;
    private final ArrayList<RemoteViews> mFieldPresentations;
    private final ArrayList<InlinePresentation> mFieldInlinePresentations;
    private final ArrayList<InlinePresentation> mFieldInlineTooltipPresentations;
    private final ArrayList<DatasetFieldFilter> mFieldFilters;
    @Nullable private final ClipData mFieldContent;
    private final RemoteViews mPresentation;
    @Nullable private final InlinePresentation mInlinePresentation;
    @Nullable private final InlinePresentation mInlineTooltipPresentation;
    private final IntentSender mAuthentication;
    @Nullable String mId;

@@ -119,10 +121,12 @@ public final class Dataset implements Parcelable {
        mFieldValues = builder.mFieldValues;
        mFieldPresentations = builder.mFieldPresentations;
        mFieldInlinePresentations = builder.mFieldInlinePresentations;
        mFieldInlineTooltipPresentations = builder.mFieldInlineTooltipPresentations;
        mFieldFilters = builder.mFieldFilters;
        mFieldContent = builder.mFieldContent;
        mPresentation = builder.mPresentation;
        mInlinePresentation = builder.mInlinePresentation;
        mInlineTooltipPresentation = builder.mInlineTooltipPresentation;
        mAuthentication = builder.mAuthentication;
        mId = builder.mId;
    }
@@ -153,6 +157,14 @@ public final class Dataset implements Parcelable {
        return inlinePresentation != null ? inlinePresentation : mInlinePresentation;
    }

    /** @hide */
    public @Nullable InlinePresentation getFieldInlineTooltipPresentation(int index) {
        final InlinePresentation inlineTooltipPresentation =
                mFieldInlineTooltipPresentations.get(index);
        return inlineTooltipPresentation != null
                ? inlineTooltipPresentation : mInlineTooltipPresentation;
    }

    /** @hide */
    public @Nullable DatasetFieldFilter getFilter(int index) {
        return mFieldFilters.get(index);
@@ -209,6 +221,10 @@ public final class Dataset implements Parcelable {
        if (mFieldInlinePresentations != null) {
            builder.append(", fieldInlinePresentations=").append(mFieldInlinePresentations.size());
        }
        if (mFieldInlineTooltipPresentations != null) {
            builder.append(", fieldInlineTooltipInlinePresentations=").append(
                    mFieldInlineTooltipPresentations.size());
        }
        if (mFieldFilters != null) {
            builder.append(", fieldFilters=").append(mFieldFilters.size());
        }
@@ -218,6 +234,9 @@ public final class Dataset implements Parcelable {
        if (mInlinePresentation != null) {
            builder.append(", hasInlinePresentation");
        }
        if (mInlineTooltipPresentation != null) {
            builder.append(", hasInlineTooltipPresentation");
        }
        if (mAuthentication != null) {
            builder.append(", hasAuthentication");
        }
@@ -245,10 +264,12 @@ public final class Dataset implements Parcelable {
        private ArrayList<AutofillValue> mFieldValues;
        private ArrayList<RemoteViews> mFieldPresentations;
        private ArrayList<InlinePresentation> mFieldInlinePresentations;
        private ArrayList<InlinePresentation> mFieldInlineTooltipPresentations;
        private ArrayList<DatasetFieldFilter> mFieldFilters;
        @Nullable private ClipData mFieldContent;
        private RemoteViews mPresentation;
        @Nullable private InlinePresentation mInlinePresentation;
        @Nullable private InlinePresentation mInlineTooltipPresentation;
        private IntentSender mAuthentication;
        private boolean mDestroyed;
        @Nullable private String mId;
@@ -305,6 +326,31 @@ public final class Dataset implements Parcelable {
            return this;
        }

        /**
         * Visualizes this dataset as inline suggestions.
         *
         * @param inlinePresentation the {@link InlinePresentation} used to visualize this
         *         dataset as inline suggestions. If the dataset supports inline suggestions this
         *         should not be null.
         * @param inlineTooltipPresentation the {@link InlinePresentation} used to show
         *         the tooltip for the {@code inlinePresentation}.
         *
         * @throws IllegalStateException if {@link #build()} was already called.
         *
         * @return this builder.
         */
        public @NonNull Builder setInlinePresentation(
                @NonNull InlinePresentation inlinePresentation,
                @NonNull InlinePresentation inlineTooltipPresentation) {
            throwIfDestroyed();
            Preconditions.checkNotNull(inlinePresentation, "inlinePresentation must be non-null");
            Preconditions.checkNotNull(inlineTooltipPresentation,
                    "inlineTooltipPresentation must be non-null");
            mInlinePresentation = inlinePresentation;
            mInlineTooltipPresentation = inlineTooltipPresentation;
            return this;
        }

        /**
         * Triggers a custom UI before before autofilling the screen with the contents of this
         * dataset.
@@ -596,6 +642,41 @@ public final class Dataset implements Parcelable {
            return this;
        }

        /**
         * Sets the value of a field, using a custom {@link RemoteViews presentation} to
         * visualize it and an {@link InlinePresentation} to visualize it as an inline suggestion.
         *
         * @see #setValue(AutofillId, AutofillValue, RemoteViews, InlinePresentation)
         *
         * @param id id returned by {@link
         *        android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
         * @param value the value to be autofilled. Pass {@code null} if you do not have the value
         *        but the target view is a logical part of the dataset. For example, if
         *        the dataset needs authentication and you have no access to the value.
         * @param presentation the presentation used to visualize this field.
         * @param inlinePresentation The {@link InlinePresentation} used to visualize this dataset
         *        as inline suggestions. If the dataset supports inline suggestions,
         *        this should not be null.
         * @param inlineTooltipPresentation The {@link InlinePresentation} used to show
         *        the tooltip for the {@code inlinePresentation}.
         *
         * @throws IllegalStateException if {@link #build()} was already called.
         *
         * @return this builder.
         */
        public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value,
                @NonNull RemoteViews presentation, @NonNull InlinePresentation inlinePresentation,
                @NonNull InlinePresentation inlineTooltipPresentation) {
            throwIfDestroyed();
            Preconditions.checkNotNull(presentation, "presentation cannot be null");
            Preconditions.checkNotNull(inlinePresentation, "inlinePresentation cannot be null");
            Preconditions.checkNotNull(inlineTooltipPresentation,
                    "inlineTooltipPresentation cannot be null");
            setLifeTheUniverseAndEverything(id, value, presentation, inlinePresentation,
                    inlineTooltipPresentation, null);
            return this;
        }

        /**
         * Sets the value of a field, using a custom {@link RemoteViews presentation} to
         * visualize it and a <a href="#Filtering">explicit filter</a>, and an
@@ -640,6 +721,47 @@ public final class Dataset implements Parcelable {
            return this;
        }

        /**
         * Sets the value of a field, using a custom {@link RemoteViews presentation} to
         * visualize it and a <a href="#Filtering">explicit filter</a>, and an
         * {@link InlinePresentation} to visualize it as an inline suggestion.
         *
         * @see #setValue(AutofillId, AutofillValue, Pattern, RemoteViews, InlinePresentation)
         *
         * @param id id returned by {@link
         *         android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
         * @param value the value to be autofilled. Pass {@code null} if you do not have the value
         *        but the target view is a logical part of the dataset. For example, if
         *        the dataset needs authentication and you have no access to the value.
         * @param filter regex used to determine if the dataset should be shown in the autofill UI;
         *        when {@code null}, it disables filtering on that dataset (this is the recommended
         *        approach when {@code value} is not {@code null} and field contains sensitive data
         *        such as passwords).
         * @param presentation the presentation used to visualize this field.
         * @param inlinePresentation The {@link InlinePresentation} used to visualize this dataset
         *        as inline suggestions. If the dataset supports inline suggestions, this
         *        should not be null.
         * @param inlineTooltipPresentation The {@link InlinePresentation} used to show
         *        the tooltip for the {@code inlinePresentation}.
         *
         * @throws IllegalStateException if {@link #build()} was already called.
         *
         * @return this builder.
         */
        public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value,
                @Nullable Pattern filter, @NonNull RemoteViews presentation,
                @NonNull InlinePresentation inlinePresentation,
                @NonNull InlinePresentation inlineTooltipPresentation) {
            throwIfDestroyed();
            Preconditions.checkNotNull(presentation, "presentation cannot be null");
            Preconditions.checkNotNull(inlinePresentation, "inlinePresentation cannot be null");
            Preconditions.checkNotNull(inlineTooltipPresentation,
                    "inlineTooltipPresentation cannot be null");
            setLifeTheUniverseAndEverything(id, value, presentation, inlinePresentation,
                    inlineTooltipPresentation, new DatasetFieldFilter(filter));
            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.
@@ -680,6 +802,15 @@ public final class Dataset implements Parcelable {
                @Nullable AutofillValue value, @Nullable RemoteViews presentation,
                @Nullable InlinePresentation inlinePresentation,
                @Nullable DatasetFieldFilter filter) {
            setLifeTheUniverseAndEverything(id, value, presentation, inlinePresentation, null,
                    filter);
        }

        private void setLifeTheUniverseAndEverything(@NonNull AutofillId id,
                @Nullable AutofillValue value, @Nullable RemoteViews presentation,
                @Nullable InlinePresentation inlinePresentation,
                @Nullable InlinePresentation tooltip,
                @Nullable DatasetFieldFilter filter) {
            Preconditions.checkNotNull(id, "id cannot be null");
            if (mFieldIds != null) {
                final int existingIdx = mFieldIds.indexOf(id);
@@ -687,6 +818,7 @@ public final class Dataset implements Parcelable {
                    mFieldValues.set(existingIdx, value);
                    mFieldPresentations.set(existingIdx, presentation);
                    mFieldInlinePresentations.set(existingIdx, inlinePresentation);
                    mFieldInlineTooltipPresentations.set(existingIdx, tooltip);
                    mFieldFilters.set(existingIdx, filter);
                    return;
                }
@@ -695,12 +827,14 @@ public final class Dataset implements Parcelable {
                mFieldValues = new ArrayList<>();
                mFieldPresentations = new ArrayList<>();
                mFieldInlinePresentations = new ArrayList<>();
                mFieldInlineTooltipPresentations = new ArrayList<>();
                mFieldFilters = new ArrayList<>();
            }
            mFieldIds.add(id);
            mFieldValues.add(value);
            mFieldPresentations.add(presentation);
            mFieldInlinePresentations.add(inlinePresentation);
            mFieldInlineTooltipPresentations.add(tooltip);
            mFieldFilters.add(filter);
        }

@@ -755,10 +889,12 @@ public final class Dataset implements Parcelable {
    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeParcelable(mPresentation, flags);
        parcel.writeParcelable(mInlinePresentation, flags);
        parcel.writeParcelable(mInlineTooltipPresentation, flags);
        parcel.writeTypedList(mFieldIds, flags);
        parcel.writeTypedList(mFieldValues, flags);
        parcel.writeTypedList(mFieldPresentations, flags);
        parcel.writeTypedList(mFieldInlinePresentations, flags);
        parcel.writeTypedList(mFieldInlineTooltipPresentations, flags);
        parcel.writeTypedList(mFieldFilters, flags);
        parcel.writeParcelable(mFieldContent, flags);
        parcel.writeParcelable(mAuthentication, flags);
@@ -770,6 +906,8 @@ public final class Dataset implements Parcelable {
        public Dataset createFromParcel(Parcel parcel) {
            final RemoteViews presentation = parcel.readParcelable(null);
            final InlinePresentation inlinePresentation = parcel.readParcelable(null);
            final InlinePresentation inlineTooltipPresentation =
                    parcel.readParcelable(null);
            final ArrayList<AutofillId> ids =
                    parcel.createTypedArrayList(AutofillId.CREATOR);
            final ArrayList<AutofillValue> values =
@@ -778,6 +916,8 @@ public final class Dataset implements Parcelable {
                    parcel.createTypedArrayList(RemoteViews.CREATOR);
            final ArrayList<InlinePresentation> inlinePresentations =
                    parcel.createTypedArrayList(InlinePresentation.CREATOR);
            final ArrayList<InlinePresentation> inlineTooltipPresentations =
                    parcel.createTypedArrayList(InlinePresentation.CREATOR);
            final ArrayList<DatasetFieldFilter> filters =
                    parcel.createTypedArrayList(DatasetFieldFilter.CREATOR);
            final ClipData fieldContent = parcel.readParcelable(null);
@@ -790,8 +930,13 @@ public final class Dataset implements Parcelable {
            final Builder builder = (presentation != null) ? new Builder(presentation)
                    : new Builder();
            if (inlinePresentation != null) {
                if (inlineTooltipPresentation != null) {
                    builder.setInlinePresentation(inlinePresentation, inlineTooltipPresentation);
                } else {
                    builder.setInlinePresentation(inlinePresentation);
                }
            }

            if (fieldContent != null) {
                builder.setContent(ids.get(0), fieldContent);
            }
@@ -802,9 +947,11 @@ public final class Dataset implements Parcelable {
                final RemoteViews fieldPresentation = presentations.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, filter);
                        fieldInlinePresentation, fieldInlineTooltipPresentation, filter);
            }
            builder.setAuthentication(authentication);
            builder.setId(datasetId);
+32 −1

File changed.

Preview size limit exceeded, changes collapsed.

+18 −4
Original line number Diff line number Diff line
@@ -75,9 +75,23 @@ public final class InlinePresentation implements Parcelable {
        return hints.toArray(new String[hints.size()]);
    }

    /**
     * Creates a presentation for the inline suggestion tooltip
     *
     * @param slice Represents the UI content and the action for the inline suggestion tooltip.
     * @param spec Specifies the UI specification for the inline suggestion tooltip.
     * @return An {@link InlinePresentation} for the inline suggestion tooltip
     */
    @NonNull
    public static InlinePresentation createTooltipPresentation(@NonNull Slice slice,
            @NonNull InlinePresentationSpec spec) {
        return new InlinePresentation(slice, spec, /* pinned */ false);

    }



    // Code below generated by codegen v1.0.20.
    // Code below generated by codegen v1.0.22.
    //
    // DO NOT MODIFY!
    // CHECKSTYLE:OFF Generated code
@@ -259,10 +273,10 @@ public final class InlinePresentation implements Parcelable {
    };

    @DataClass.Generated(
            time = 1604456277638L,
            codegenVersion = "1.0.20",
            time = 1615968415006L,
            codegenVersion = "1.0.22",
            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.widget.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final  boolean mPinned\npublic @android.annotation.NonNull @android.annotation.Size java.lang.String[] getAutofillHints()\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.widget.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final  boolean mPinned\npublic @android.annotation.NonNull @android.annotation.Size java.lang.String[] getAutofillHints()\npublic static @android.annotation.NonNull android.service.autofill.InlinePresentation createTooltipPresentation(android.app.slice.Slice,android.widget.inline.InlinePresentationSpec)\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() {}

+149 −11

File changed.

Preview size limit exceeded, changes collapsed.