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

Commit 2e853aa1 authored by Tony Mak's avatar Tony Mak
Browse files

Introduce TextSelection.Builder.setIncludeTextClassification and...

Introduce TextSelection.Builder.setIncludeTextClassification and TextSelection.getTextClassification()

This small API change enables us to optimize the latnecy of smart
selection.

To enable smart selection, TextView/WebView always call
textClassifier.suggestSelection and textClassifier.classifyText back to
back. There are a lot of overlaps between suggestSelection and
classifyText, e.g. both API calls classify the entity type of the text.
This optimization is important to make smart selection working
responsively, especially that we enforce a 200ms timeout in TextView.

This small API change allows the TextClassifier to implement smart
selection with just one single API call.

This change is backward-compatible.
If the text classifier is not updated to return the text classification
result in suggestSelection yet, clients can learn that by checking if
textSelection.getTextClassification() returns null. If so, the client
can then fallback to call ClassifyText().

You may find the textview integration in ag/13092679

Design doc: go/android-s-suggestselection

Bug: 173512834

Test: atest TextSelectionTest
Change-Id: If4cc827aa19d6d14c885cf10cd5ba16aa3041cf6
parent 68a3422b
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -56539,6 +56539,7 @@ package android.view.textclassifier {
    method @Nullable public String getId();
    method @Nullable public String getId();
    method public int getSelectionEndIndex();
    method public int getSelectionEndIndex();
    method public int getSelectionStartIndex();
    method public int getSelectionStartIndex();
    method @Nullable public android.view.textclassifier.TextClassification getTextClassification();
    method public void writeToParcel(android.os.Parcel, int);
    method public void writeToParcel(android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextSelection> CREATOR;
    field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextSelection> CREATOR;
  }
  }
@@ -56549,6 +56550,7 @@ package android.view.textclassifier {
    method @NonNull public android.view.textclassifier.TextSelection.Builder setEntityType(@NonNull String, @FloatRange(from=0.0, to=1.0) float);
    method @NonNull public android.view.textclassifier.TextSelection.Builder setEntityType(@NonNull String, @FloatRange(from=0.0, to=1.0) float);
    method @NonNull public android.view.textclassifier.TextSelection.Builder setExtras(@Nullable android.os.Bundle);
    method @NonNull public android.view.textclassifier.TextSelection.Builder setExtras(@Nullable android.os.Bundle);
    method @NonNull public android.view.textclassifier.TextSelection.Builder setId(@Nullable String);
    method @NonNull public android.view.textclassifier.TextSelection.Builder setId(@Nullable String);
    method @NonNull public android.view.textclassifier.TextSelection.Builder setTextClassification(@Nullable android.view.textclassifier.TextClassification);
  }
  }
  public static final class TextSelection.Request implements android.os.Parcelable {
  public static final class TextSelection.Request implements android.os.Parcelable {
@@ -56559,6 +56561,7 @@ package android.view.textclassifier {
    method @NonNull public android.os.Bundle getExtras();
    method @NonNull public android.os.Bundle getExtras();
    method @IntRange(from=0) public int getStartIndex();
    method @IntRange(from=0) public int getStartIndex();
    method @NonNull public CharSequence getText();
    method @NonNull public CharSequence getText();
    method public boolean shouldIncludeTextClassification();
    method public void writeToParcel(android.os.Parcel, int);
    method public void writeToParcel(android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextSelection.Request> CREATOR;
    field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextSelection.Request> CREATOR;
  }
  }
@@ -56568,6 +56571,7 @@ package android.view.textclassifier {
    method @NonNull public android.view.textclassifier.TextSelection.Request build();
    method @NonNull public android.view.textclassifier.TextSelection.Request build();
    method @NonNull public android.view.textclassifier.TextSelection.Request.Builder setDefaultLocales(@Nullable android.os.LocaleList);
    method @NonNull public android.view.textclassifier.TextSelection.Request.Builder setDefaultLocales(@Nullable android.os.LocaleList);
    method @NonNull public android.view.textclassifier.TextSelection.Request.Builder setExtras(@Nullable android.os.Bundle);
    method @NonNull public android.view.textclassifier.TextSelection.Request.Builder setExtras(@Nullable android.os.Bundle);
    method @NonNull public android.view.textclassifier.TextSelection.Request.Builder setIncludeTextClassification(boolean);
  }
  }
}
}
+68 −3
Original line number Original line Diff line number Diff line
@@ -45,15 +45,19 @@ public final class TextSelection implements Parcelable {
    private final int mEndIndex;
    private final int mEndIndex;
    private final EntityConfidence mEntityConfidence;
    private final EntityConfidence mEntityConfidence;
    @Nullable private final String mId;
    @Nullable private final String mId;
    @Nullable
    private final TextClassification mTextClassification;
    private final Bundle mExtras;
    private final Bundle mExtras;


    private TextSelection(
    private TextSelection(
            int startIndex, int endIndex, Map<String, Float> entityConfidence, String id,
            int startIndex, int endIndex, Map<String, Float> entityConfidence, String id,
            @Nullable TextClassification textClassification,
            Bundle extras) {
            Bundle extras) {
        mStartIndex = startIndex;
        mStartIndex = startIndex;
        mEndIndex = endIndex;
        mEndIndex = endIndex;
        mEntityConfidence = new EntityConfidence(entityConfidence);
        mEntityConfidence = new EntityConfidence(entityConfidence);
        mId = id;
        mId = id;
        mTextClassification = textClassification;
        mExtras = extras;
        mExtras = extras;
    }
    }


@@ -110,6 +114,19 @@ public final class TextSelection implements Parcelable {
        return mId;
        return mId;
    }
    }


    /**
     * Returns the text classification result of the suggested selection span. Enables the text
     * classification by calling
     * {@link TextSelection.Request.Builder#setIncludeTextClassification(boolean)}. If the text
     * classifier does not support it, a {@code null} is returned.
     *
     * @see TextSelection.Request.Builder#setIncludeTextClassification(boolean)
     */
    @Nullable
    public TextClassification getTextClassification() {
        return mTextClassification;
    }

    /**
    /**
     * Returns the extended data.
     * Returns the extended data.
     *
     *
@@ -138,6 +155,8 @@ public final class TextSelection implements Parcelable {
        private final Map<String, Float> mEntityConfidence = new ArrayMap<>();
        private final Map<String, Float> mEntityConfidence = new ArrayMap<>();
        @Nullable private String mId;
        @Nullable private String mId;
        @Nullable
        @Nullable
        private TextClassification mTextClassification;
        @Nullable
        private Bundle mExtras;
        private Bundle mExtras;


        /**
        /**
@@ -178,6 +197,21 @@ public final class TextSelection implements Parcelable {
            return this;
            return this;
        }
        }


        /**
         * Sets the text classification result of the suggested selection. If
         * {@link Request#shouldIncludeTextClassification()} is {@code true}, set this value.
         * Otherwise this value may be set to null. The intention of this method is to avoid
         * doing expensive work if the client is not interested in such result.
         *
         * @return this builder
         * @see Request#shouldIncludeTextClassification()
         */
        @NonNull
        public Builder setTextClassification(@Nullable TextClassification textClassification) {
            mTextClassification = textClassification;
            return this;
        }

        /**
        /**
         * Sets the extended data.
         * Sets the extended data.
         *
         *
@@ -196,7 +230,7 @@ public final class TextSelection implements Parcelable {
        public TextSelection build() {
        public TextSelection build() {
            return new TextSelection(
            return new TextSelection(
                    mStartIndex, mEndIndex, mEntityConfidence, mId,
                    mStartIndex, mEndIndex, mEntityConfidence, mId,
                    mExtras == null ? Bundle.EMPTY : mExtras);
                    mTextClassification, mExtras == null ? Bundle.EMPTY : mExtras);
        }
        }
    }
    }


@@ -210,6 +244,7 @@ public final class TextSelection implements Parcelable {
        private final int mEndIndex;
        private final int mEndIndex;
        @Nullable private final LocaleList mDefaultLocales;
        @Nullable private final LocaleList mDefaultLocales;
        private final boolean mDarkLaunchAllowed;
        private final boolean mDarkLaunchAllowed;
        private final boolean mIncludeTextClassification;
        private final Bundle mExtras;
        private final Bundle mExtras;
        @Nullable private SystemTextClassifierMetadata mSystemTcMetadata;
        @Nullable private SystemTextClassifierMetadata mSystemTcMetadata;


@@ -219,12 +254,14 @@ public final class TextSelection implements Parcelable {
                int endIndex,
                int endIndex,
                LocaleList defaultLocales,
                LocaleList defaultLocales,
                boolean darkLaunchAllowed,
                boolean darkLaunchAllowed,
                boolean includeTextClassification,
                Bundle extras) {
                Bundle extras) {
            mText = text;
            mText = text;
            mStartIndex = startIndex;
            mStartIndex = startIndex;
            mEndIndex = endIndex;
            mEndIndex = endIndex;
            mDefaultLocales = defaultLocales;
            mDefaultLocales = defaultLocales;
            mDarkLaunchAllowed = darkLaunchAllowed;
            mDarkLaunchAllowed = darkLaunchAllowed;
            mIncludeTextClassification = includeTextClassification;
            mExtras = extras;
            mExtras = extras;
        }
        }


@@ -302,6 +339,14 @@ public final class TextSelection implements Parcelable {
            return mSystemTcMetadata;
            return mSystemTcMetadata;
        }
        }


        /**
         * Returns true if the client wants the text classifier to classify the text as well and
         * include a {@link TextClassification} object in the result.
         */
        public boolean shouldIncludeTextClassification() {
            return mIncludeTextClassification;
        }

        /**
        /**
         * Returns the extended data.
         * Returns the extended data.
         *
         *
@@ -320,9 +365,9 @@ public final class TextSelection implements Parcelable {
            private final CharSequence mText;
            private final CharSequence mText;
            private final int mStartIndex;
            private final int mStartIndex;
            private final int mEndIndex;
            private final int mEndIndex;

            @Nullable private LocaleList mDefaultLocales;
            @Nullable private LocaleList mDefaultLocales;
            private boolean mDarkLaunchAllowed;
            private boolean mDarkLaunchAllowed;
            private boolean mIncludeTextClassification;
            private Bundle mExtras;
            private Bundle mExtras;


            /**
            /**
@@ -371,6 +416,21 @@ public final class TextSelection implements Parcelable {
                return this;
                return this;
            }
            }


            /**
             * @param includeTextClassification If true, suggests the TextClassifier to classify the
             *     text in the suggested selection span and include a TextClassification object in
             *     the result. The TextClassifier may not support this and in which case,
             *     {@link TextSelection#getTextClassification()} returns {@code null}.
             *
             * @return this builder.
             * @see TextSelection#getTextClassification()
             */
            @NonNull
            public Builder setIncludeTextClassification(boolean includeTextClassification) {
                mIncludeTextClassification = includeTextClassification;
                return this;
            }

            /**
            /**
             * Sets the extended data.
             * Sets the extended data.
             *
             *
@@ -389,6 +449,7 @@ public final class TextSelection implements Parcelable {
            public Request build() {
            public Request build() {
                return new Request(new SpannedString(mText), mStartIndex, mEndIndex,
                return new Request(new SpannedString(mText), mStartIndex, mEndIndex,
                        mDefaultLocales, mDarkLaunchAllowed,
                        mDefaultLocales, mDarkLaunchAllowed,
                        mIncludeTextClassification,
                        mExtras == null ? Bundle.EMPTY : mExtras);
                        mExtras == null ? Bundle.EMPTY : mExtras);
            }
            }
        }
        }
@@ -406,6 +467,7 @@ public final class TextSelection implements Parcelable {
            dest.writeParcelable(mDefaultLocales, flags);
            dest.writeParcelable(mDefaultLocales, flags);
            dest.writeBundle(mExtras);
            dest.writeBundle(mExtras);
            dest.writeParcelable(mSystemTcMetadata, flags);
            dest.writeParcelable(mSystemTcMetadata, flags);
            dest.writeBoolean(mIncludeTextClassification);
        }
        }


        private static Request readFromParcel(Parcel in) {
        private static Request readFromParcel(Parcel in) {
@@ -415,9 +477,10 @@ public final class TextSelection implements Parcelable {
            final LocaleList defaultLocales = in.readParcelable(null);
            final LocaleList defaultLocales = in.readParcelable(null);
            final Bundle extras = in.readBundle();
            final Bundle extras = in.readBundle();
            final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
            final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
            final boolean includeTextClassification = in.readBoolean();


            final Request request = new Request(text, startIndex, endIndex, defaultLocales,
            final Request request = new Request(text, startIndex, endIndex, defaultLocales,
                    /* darkLaunchAllowed= */ false, extras);
                    /* darkLaunchAllowed= */ false, includeTextClassification, extras);
            request.setSystemTextClassifierMetadata(systemTcMetadata);
            request.setSystemTextClassifierMetadata(systemTcMetadata);
            return request;
            return request;
        }
        }
@@ -448,6 +511,7 @@ public final class TextSelection implements Parcelable {
        mEntityConfidence.writeToParcel(dest, flags);
        mEntityConfidence.writeToParcel(dest, flags);
        dest.writeString(mId);
        dest.writeString(mId);
        dest.writeBundle(mExtras);
        dest.writeBundle(mExtras);
        dest.writeParcelable(mTextClassification, flags);
    }
    }


    public static final @android.annotation.NonNull Parcelable.Creator<TextSelection> CREATOR =
    public static final @android.annotation.NonNull Parcelable.Creator<TextSelection> CREATOR =
@@ -469,5 +533,6 @@ public final class TextSelection implements Parcelable {
        mEntityConfidence = EntityConfidence.CREATOR.createFromParcel(in);
        mEntityConfidence = EntityConfidence.CREATOR.createFromParcel(in);
        mId = in.readString();
        mId = in.readString();
        mExtras = in.readBundle();
        mExtras = in.readBundle();
        mTextClassification = in.readParcelable(TextClassification.class.getClassLoader());
    }
    }
}
}