diff options
12 files changed, 297 insertions, 136 deletions
diff --git a/api/current.txt b/api/current.txt index 3967896d76fe..3422030c0c10 100644 --- a/api/current.txt +++ b/api/current.txt @@ -52044,6 +52044,7 @@ package android.view.textclassifier { public static final class ConversationActions.Request implements android.os.Parcelable { method public int describeContents(); + method public java.lang.String getCallingPackageName(); method public java.util.List<android.view.textclassifier.ConversationActions.Message> getConversation(); method public java.util.List<java.lang.String> getHints(); method public int getMaxSuggestions(); @@ -52157,6 +52158,7 @@ package android.view.textclassifier { public static final class TextClassification.Request implements android.os.Parcelable { method public int describeContents(); + method public java.lang.String getCallingPackageName(); method public android.os.LocaleList getDefaultLocales(); method public int getEndIndex(); method public android.os.Bundle getExtras(); @@ -52274,6 +52276,7 @@ package android.view.textclassifier { public static final class TextLanguage.Request implements android.os.Parcelable { method public int describeContents(); + method public java.lang.String getCallingPackageName(); method public android.os.Bundle getExtras(); method public java.lang.CharSequence getText(); method public void writeToParcel(android.os.Parcel, int); @@ -52305,6 +52308,7 @@ package android.view.textclassifier { public static final class TextLinks.Builder { ctor public TextLinks.Builder(java.lang.String); method public android.view.textclassifier.TextLinks.Builder addLink(int, int, java.util.Map<java.lang.String, java.lang.Float>); + method public android.view.textclassifier.TextLinks.Builder addLink(int, int, java.util.Map<java.lang.String, java.lang.Float>, android.os.Bundle); method public android.view.textclassifier.TextLinks build(); method public android.view.textclassifier.TextLinks.Builder clearTextLinks(); method public android.view.textclassifier.TextLinks.Builder setExtras(android.os.Bundle); @@ -52312,6 +52316,7 @@ package android.view.textclassifier { public static final class TextLinks.Request implements android.os.Parcelable { method public int describeContents(); + method public java.lang.String getCallingPackageName(); method public android.os.LocaleList getDefaultLocales(); method public android.view.textclassifier.TextClassifier.EntityConfig getEntityConfig(); method public android.os.Bundle getExtras(); @@ -52334,6 +52339,7 @@ package android.view.textclassifier { method public int getEnd(); method public java.lang.String getEntity(int); method public int getEntityCount(); + method public android.os.Bundle getExtras(); method public int getStart(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextLinks.TextLink> CREATOR; @@ -52368,6 +52374,7 @@ package android.view.textclassifier { public static final class TextSelection.Request implements android.os.Parcelable { method public int describeContents(); + method public java.lang.String getCallingPackageName(); method public android.os.LocaleList getDefaultLocales(); method public int getEndIndex(); method public android.os.Bundle getExtras(); diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java index 1a7b91127a7b..04b94b0e03ad 100644 --- a/core/java/android/view/textclassifier/ConversationActions.java +++ b/core/java/android/view/textclassifier/ConversationActions.java @@ -30,6 +30,7 @@ import android.os.Parcelable; import android.text.SpannedString; import android.util.ArraySet; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; @@ -654,6 +655,8 @@ public final class ConversationActions implements Parcelable { @NonNull @Hint private final List<String> mHints; + @Nullable + private String mCallingPackageName; private Request( @NonNull List<Message> conversation, @@ -666,15 +669,26 @@ public final class ConversationActions implements Parcelable { mHints = hints; } - private Request(Parcel in) { + private static Request readFromParcel(Parcel in) { List<Message> conversation = new ArrayList<>(); in.readParcelableList(conversation, null); - mConversation = Collections.unmodifiableList(conversation); - mTypeConfig = in.readParcelable(null); - mMaxSuggestions = in.readInt(); + + TypeConfig typeConfig = in.readParcelable(null); + + int maxSuggestions = in.readInt(); + List<String> hints = new ArrayList<>(); in.readStringList(hints); - mHints = Collections.unmodifiableList(hints); + + String callingPackageName = in.readString(); + + Request request = new Request( + conversation, + typeConfig, + maxSuggestions, + hints); + request.setCallingPackageName(callingPackageName); + return request; } @Override @@ -683,6 +697,7 @@ public final class ConversationActions implements Parcelable { parcel.writeParcelable(mTypeConfig, flags); parcel.writeInt(mMaxSuggestions); parcel.writeStringList(mHints); + parcel.writeString(mCallingPackageName); } @Override @@ -694,7 +709,7 @@ public final class ConversationActions implements Parcelable { new Creator<Request>() { @Override public Request createFromParcel(Parcel in) { - return new Request(in); + return readFromParcel(in); } @Override @@ -730,6 +745,26 @@ public final class ConversationActions implements Parcelable { return mHints; } + /** + * Sets the name of the package that is sending this request. + * <p> + * Package-private for SystemTextClassifier's use. + * @hide + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void setCallingPackageName(@Nullable String callingPackageName) { + mCallingPackageName = callingPackageName; + } + + /** + * Returns the name of the package that sent this request. + * This returns {@code null} if no calling package name is set. + */ + @Nullable + public String getCallingPackageName() { + return mCallingPackageName; + } + /** Builder object to construct the {@link Request} object. */ public static final class Builder { @NonNull diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java index f8fce62c84d2..c24489c8740b 100644 --- a/core/java/android/view/textclassifier/SystemTextClassifier.java +++ b/core/java/android/view/textclassifier/SystemTextClassifier.java @@ -60,7 +60,7 @@ public final class SystemTextClassifier implements TextClassifier { mSettings = Preconditions.checkNotNull(settings); mFallback = context.getSystemService(TextClassificationManager.class) .getTextClassifier(TextClassifier.LOCAL); - mPackageName = Preconditions.checkNotNull(context.getPackageName()); + mPackageName = Preconditions.checkNotNull(context.getOpPackageName()); } /** @@ -72,6 +72,7 @@ public final class SystemTextClassifier implements TextClassifier { Preconditions.checkNotNull(request); Utils.checkMainThread(); try { + request.setCallingPackageName(mPackageName); final TextSelectionCallback callback = new TextSelectionCallback(); mManagerService.onSuggestSelection(mSessionId, request, callback); final TextSelection selection = callback.mReceiver.get(); @@ -93,6 +94,7 @@ public final class SystemTextClassifier implements TextClassifier { Preconditions.checkNotNull(request); Utils.checkMainThread(); try { + request.setCallingPackageName(mPackageName); final TextClassificationCallback callback = new TextClassificationCallback(); mManagerService.onClassifyText(mSessionId, request, callback); final TextClassification classification = callback.mReceiver.get(); @@ -150,6 +152,7 @@ public final class SystemTextClassifier implements TextClassifier { Utils.checkMainThread(); try { + request.setCallingPackageName(mPackageName); final TextLanguageCallback callback = new TextLanguageCallback(); mManagerService.onDetectLanguage(mSessionId, request, callback); final TextLanguage textLanguage = callback.mReceiver.get(); @@ -168,6 +171,7 @@ public final class SystemTextClassifier implements TextClassifier { Utils.checkMainThread(); try { + request.setCallingPackageName(mPackageName); final ConversationActionsCallback callback = new ConversationActionsCallback(); mManagerService.onSuggestConversationActions(mSessionId, request, callback); final ConversationActions conversationActions = callback.mReceiver.get(); diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java index e0910c0b37b7..d9f79655d588 100644 --- a/core/java/android/view/textclassifier/TextClassification.java +++ b/core/java/android/view/textclassifier/TextClassification.java @@ -37,11 +37,13 @@ import android.os.Bundle; import android.os.LocaleList; import android.os.Parcel; import android.os.Parcelable; +import android.text.SpannedString; import android.util.ArrayMap; import android.view.View.OnClickListener; import android.view.textclassifier.TextClassifier.EntityType; import android.view.textclassifier.TextClassifier.Utils; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; @@ -518,6 +520,7 @@ public final class TextClassification implements Parcelable { @Nullable private final LocaleList mDefaultLocales; @Nullable private final ZonedDateTime mReferenceTime; @NonNull private final Bundle mExtras; + @Nullable private String mCallingPackageName; private Request( CharSequence text, @@ -578,6 +581,26 @@ public final class TextClassification implements Parcelable { } /** + * Sets the name of the package that is sending this request. + * <p> + * For SystemTextClassifier's use. + * @hide + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void setCallingPackageName(@Nullable String callingPackageName) { + mCallingPackageName = callingPackageName; + } + + /** + * Returns the name of the package that sent this request. + * This returns {@code null} if no calling package name is set. + */ + @Nullable + public String getCallingPackageName() { + return mCallingPackageName; + } + + /** * Returns the extended data. * * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should @@ -660,7 +683,8 @@ public final class TextClassification implements Parcelable { */ @NonNull public Request build() { - return new Request(mText, mStartIndex, mEndIndex, mDefaultLocales, mReferenceTime, + return new Request(new SpannedString(mText), mStartIndex, mEndIndex, + mDefaultLocales, mReferenceTime, mExtras == null ? Bundle.EMPTY : mExtras.deepCopy()); } } @@ -672,25 +696,37 @@ public final class TextClassification implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mText.toString()); + dest.writeCharSequence(mText); dest.writeInt(mStartIndex); dest.writeInt(mEndIndex); - dest.writeInt(mDefaultLocales != null ? 1 : 0); - if (mDefaultLocales != null) { - mDefaultLocales.writeToParcel(dest, flags); - } - dest.writeInt(mReferenceTime != null ? 1 : 0); - if (mReferenceTime != null) { - dest.writeString(mReferenceTime.toString()); - } + dest.writeParcelable(mDefaultLocales, flags); + dest.writeString(mReferenceTime == null ? null : mReferenceTime.toString()); + dest.writeString(mCallingPackageName); dest.writeBundle(mExtras); } + private static Request readFromParcel(Parcel in) { + final CharSequence text = in.readCharSequence(); + final int startIndex = in.readInt(); + final int endIndex = in.readInt(); + final LocaleList defaultLocales = in.readParcelable(null); + final String referenceTimeString = in.readString(); + final ZonedDateTime referenceTime = referenceTimeString == null + ? null : ZonedDateTime.parse(referenceTimeString); + final String callingPackageName = in.readString(); + final Bundle extras = in.readBundle(); + + final Request request = new Request(text, startIndex, endIndex, + defaultLocales, referenceTime, extras); + request.setCallingPackageName(callingPackageName); + return request; + } + public static final Parcelable.Creator<Request> CREATOR = new Parcelable.Creator<Request>() { @Override public Request createFromParcel(Parcel in) { - return new Request(in); + return readFromParcel(in); } @Override @@ -698,15 +734,6 @@ public final class TextClassification implements Parcelable { return new Request[size]; } }; - - private Request(Parcel in) { - mText = in.readString(); - mStartIndex = in.readInt(); - mEndIndex = in.readInt(); - mDefaultLocales = in.readInt() == 0 ? null : LocaleList.CREATOR.createFromParcel(in); - mReferenceTime = in.readInt() == 0 ? null : ZonedDateTime.parse(in.readString()); - mExtras = in.readBundle(); - } } @Override diff --git a/core/java/android/view/textclassifier/TextLanguage.java b/core/java/android/view/textclassifier/TextLanguage.java index d28459e733f0..b1609fcfe56a 100644 --- a/core/java/android/view/textclassifier/TextLanguage.java +++ b/core/java/android/view/textclassifier/TextLanguage.java @@ -26,6 +26,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.ArrayMap; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.util.Locale; @@ -90,7 +91,7 @@ public final class TextLanguage implements Parcelable { * confidence to low confidence. * * @throws IndexOutOfBoundsException if the specified index is out of range. - * @see #getLocaleCount() for the number of locales available. + * @see #getLocaleHypothesisCount() for the number of locales available. */ @NonNull public ULocale getLocale(int index) { @@ -222,11 +223,12 @@ public final class TextLanguage implements Parcelable { }; private final CharSequence mText; - private final Bundle mBundle; + private final Bundle mExtra; + @Nullable private String mCallingPackageName; private Request(CharSequence text, Bundle bundle) { mText = text; - mBundle = bundle; + mExtra = bundle; } /** @@ -238,6 +240,25 @@ public final class TextLanguage implements Parcelable { } /** + * Sets the name of the package that is sending this request. + * Package-private for SystemTextClassifier's use. + * @hide + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void setCallingPackageName(@Nullable String callingPackageName) { + mCallingPackageName = callingPackageName; + } + + /** + * Returns the name of the package that sent this request. + * This returns null if no calling package name is set. + */ + @Nullable + public String getCallingPackageName() { + return mCallingPackageName; + } + + /** * Returns a bundle containing non-structured extra information about this request. * * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should @@ -246,7 +267,7 @@ public final class TextLanguage implements Parcelable { */ @NonNull public Bundle getExtras() { - return mBundle.deepCopy(); + return mExtra.deepCopy(); } @Override @@ -257,13 +278,18 @@ public final class TextLanguage implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeCharSequence(mText); - dest.writeBundle(mBundle); + dest.writeString(mCallingPackageName); + dest.writeBundle(mExtra); } private static Request readFromParcel(Parcel in) { - return new Request( - in.readCharSequence(), - in.readBundle()); + final CharSequence text = in.readCharSequence(); + final String callingPackageName = in.readString(); + final Bundle extra = in.readBundle(); + + final Request request = new Request(text, extra); + request.setCallingPackageName(callingPackageName); + return request; } /** diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java index 1e42c414a365..ab341782ac58 100644 --- a/core/java/android/view/textclassifier/TextLinks.java +++ b/core/java/android/view/textclassifier/TextLinks.java @@ -30,6 +30,7 @@ import android.text.method.MovementMethod; import android.text.style.ClickableSpan; import android.text.style.URLSpan; import android.view.View; +import android.view.textclassifier.TextClassifier.EntityConfig; import android.view.textclassifier.TextClassifier.EntityType; import android.widget.TextView; @@ -205,27 +206,32 @@ public final class TextLinks implements Parcelable { private final EntityConfidence mEntityScores; private final int mStart; private final int mEnd; - @Nullable final URLSpan mUrlSpan; + private final Bundle mExtras; + @Nullable private final URLSpan mUrlSpan; /** * Create a new TextLink. * * @param start The start index of the identified subsequence * @param end The end index of the identified subsequence - * @param entityScores A mapping of entity type to confidence score + * @param entityConfidence A mapping of entity type to confidence score + * @param extras A bundle containing custom data related to this TextLink * @param urlSpan An optional URLSpan to delegate to. NOTE: Not parcelled * - * @throws IllegalArgumentException if entityScores is null or empty + * @throws IllegalArgumentException if {@code entityConfidence} is null or empty + * @throws IllegalArgumentException if {@code start} is greater than {@code end} */ - TextLink(int start, int end, Map<String, Float> entityScores, - @Nullable URLSpan urlSpan) { - Preconditions.checkNotNull(entityScores); - Preconditions.checkArgument(!entityScores.isEmpty()); + private TextLink(int start, int end, @NonNull EntityConfidence entityConfidence, + @NonNull Bundle extras, @Nullable URLSpan urlSpan) { + Preconditions.checkNotNull(entityConfidence); + Preconditions.checkArgument(!entityConfidence.getEntities().isEmpty()); Preconditions.checkArgument(start <= end); + Preconditions.checkNotNull(extras); mStart = start; mEnd = end; - mEntityScores = new EntityConfidence(entityScores); + mEntityScores = entityConfidence; mUrlSpan = urlSpan; + mExtras = extras; } /** @@ -274,6 +280,13 @@ public final class TextLinks implements Parcelable { return mEntityScores.getConfidenceScore(entityType); } + /** + * Returns a bundle containing custom data related to this TextLink. + */ + public Bundle getExtras() { + return mExtras; + } + @Override public String toString() { return String.format(Locale.US, @@ -291,13 +304,22 @@ public final class TextLinks implements Parcelable { mEntityScores.writeToParcel(dest, flags); dest.writeInt(mStart); dest.writeInt(mEnd); + dest.writeBundle(mExtras); + } + + private static TextLink readFromParcel(Parcel in) { + final EntityConfidence entityConfidence = EntityConfidence.CREATOR.createFromParcel(in); + final int start = in.readInt(); + final int end = in.readInt(); + final Bundle extras = in.readBundle(); + return new TextLink(start, end, entityConfidence, extras, null /* urlSpan */); } public static final Parcelable.Creator<TextLink> CREATOR = new Parcelable.Creator<TextLink>() { @Override public TextLink createFromParcel(Parcel in) { - return new TextLink(in); + return readFromParcel(in); } @Override @@ -305,13 +327,6 @@ public final class TextLinks implements Parcelable { return new TextLink[size]; } }; - - private TextLink(Parcel in) { - mEntityScores = EntityConfidence.CREATOR.createFromParcel(in); - mStart = in.readInt(); - mEnd = in.readInt(); - mUrlSpan = null; - } } /** @@ -321,23 +336,21 @@ public final class TextLinks implements Parcelable { private final CharSequence mText; @Nullable private final LocaleList mDefaultLocales; - @Nullable private final TextClassifier.EntityConfig mEntityConfig; + @Nullable private final EntityConfig mEntityConfig; private final boolean mLegacyFallback; - private String mCallingPackageName; + @Nullable private String mCallingPackageName; private final Bundle mExtras; private Request( CharSequence text, LocaleList defaultLocales, - TextClassifier.EntityConfig entityConfig, + EntityConfig entityConfig, boolean legacyFallback, - String callingPackageName, Bundle extras) { mText = text; mDefaultLocales = defaultLocales; mEntityConfig = entityConfig; mLegacyFallback = legacyFallback; - mCallingPackageName = callingPackageName; mExtras = extras; } @@ -360,10 +373,10 @@ public final class TextLinks implements Parcelable { /** * @return The config representing the set of entities to look for - * @see Builder#setEntityConfig(TextClassifier.EntityConfig) + * @see Builder#setEntityConfig(EntityConfig) */ @Nullable - public TextClassifier.EntityConfig getEntityConfig() { + public EntityConfig getEntityConfig() { return mEntityConfig; } @@ -378,13 +391,26 @@ public final class TextLinks implements Parcelable { } /** - * Sets the name of the package that requested the links to get generated. + * Sets the name of the package that is sending this request. + * <p> + * Package-private for SystemTextClassifier's use. + * @hide */ - void setCallingPackageName(@Nullable String callingPackageName) { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void setCallingPackageName(@Nullable String callingPackageName) { mCallingPackageName = callingPackageName; } /** + * Returns the name of the package that sent this request. + * This returns {@code null} if no calling package name is set. + */ + @Nullable + public String getCallingPackageName() { + return mCallingPackageName; + } + + /** * Returns the extended data. * * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should @@ -404,9 +430,8 @@ public final class TextLinks implements Parcelable { private final CharSequence mText; @Nullable private LocaleList mDefaultLocales; - @Nullable private TextClassifier.EntityConfig mEntityConfig; + @Nullable private EntityConfig mEntityConfig; private boolean mLegacyFallback = true; // Use legacy fall back by default. - private String mCallingPackageName; @Nullable private Bundle mExtras; public Builder(@NonNull CharSequence text) { @@ -434,7 +459,7 @@ public final class TextLinks implements Parcelable { * @return this builder */ @NonNull - public Builder setEntityConfig(@Nullable TextClassifier.EntityConfig entityConfig) { + public Builder setEntityConfig(@Nullable EntityConfig entityConfig) { mEntityConfig = entityConfig; return this; } @@ -455,18 +480,6 @@ public final class TextLinks implements Parcelable { } /** - * Sets the name of the package that requested the links to get generated. - * - * @return this builder - * @hide - */ - @NonNull - public Builder setCallingPackageName(@Nullable String callingPackageName) { - mCallingPackageName = callingPackageName; - return this; - } - - /** * Sets the extended data. * * @return this builder @@ -483,21 +496,11 @@ public final class TextLinks implements Parcelable { public Request build() { return new Request( mText, mDefaultLocales, mEntityConfig, - mLegacyFallback, mCallingPackageName, + mLegacyFallback, mExtras == null ? Bundle.EMPTY : mExtras.deepCopy()); } } - /** - * @return the name of the package that requested the links to get generated. - * TODO: make available as system API - * @hide - */ - @Nullable - public String getCallingPackageName() { - return mCallingPackageName; - } - @Override public int describeContents() { return 0; @@ -506,23 +509,30 @@ public final class TextLinks implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(mText.toString()); - dest.writeInt(mDefaultLocales != null ? 1 : 0); - if (mDefaultLocales != null) { - mDefaultLocales.writeToParcel(dest, flags); - } - dest.writeInt(mEntityConfig != null ? 1 : 0); - if (mEntityConfig != null) { - mEntityConfig.writeToParcel(dest, flags); - } + dest.writeParcelable(mDefaultLocales, flags); + dest.writeParcelable(mEntityConfig, flags); dest.writeString(mCallingPackageName); dest.writeBundle(mExtras); } + private static Request readFromParcel(Parcel in) { + final String text = in.readString(); + final LocaleList defaultLocales = in.readParcelable(null); + final EntityConfig entityConfig = in.readParcelable(null); + final String callingPackageName = in.readString(); + final Bundle extras = in.readBundle(); + + final Request request = new Request(text, defaultLocales, entityConfig, + /* legacyFallback= */ true, extras); + request.setCallingPackageName(callingPackageName); + return request; + } + public static final Parcelable.Creator<Request> CREATOR = new Parcelable.Creator<Request>() { @Override public Request createFromParcel(Parcel in) { - return new Request(in); + return readFromParcel(in); } @Override @@ -530,16 +540,6 @@ public final class TextLinks implements Parcelable { return new Request[size]; } }; - - private Request(Parcel in) { - mText = in.readString(); - mDefaultLocales = in.readInt() == 0 ? null : LocaleList.CREATOR.createFromParcel(in); - mEntityConfig = in.readInt() == 0 - ? null : TextClassifier.EntityConfig.CREATOR.createFromParcel(in); - mLegacyFallback = true; - mCallingPackageName = in.readString(); - mExtras = in.readBundle(); - } } /** @@ -645,9 +645,20 @@ public final class TextLinks implements Parcelable { * @throws IllegalArgumentException if entityScores is null or empty. */ @NonNull - public Builder addLink(int start, int end, Map<String, Float> entityScores) { - mLinks.add(new TextLink(start, end, entityScores, null)); - return this; + public Builder addLink(int start, int end, @NonNull Map<String, Float> entityScores) { + return addLink(start, end, entityScores, Bundle.EMPTY, null); + } + + /** + * Adds a TextLink. + * + * @see #addLink(int, int, Map) + * @param extras An optional bundle containing custom data related to this TextLink + */ + @NonNull + public Builder addLink(int start, int end, @NonNull Map<String, Float> entityScores, + @NonNull Bundle extras) { + return addLink(start, end, entityScores, extras, null); } /** @@ -655,9 +666,15 @@ public final class TextLinks implements Parcelable { * @param urlSpan An optional URLSpan to delegate to. NOTE: Not parcelled. */ @NonNull - Builder addLink(int start, int end, Map<String, Float> entityScores, + Builder addLink(int start, int end, @NonNull Map<String, Float> entityScores, @Nullable URLSpan urlSpan) { - mLinks.add(new TextLink(start, end, entityScores, urlSpan)); + return addLink(start, end, entityScores, Bundle.EMPTY, urlSpan); + } + + private Builder addLink(int start, int end, @NonNull Map<String, Float> entityScores, + @NonNull Bundle extras, @Nullable URLSpan urlSpan) { + mLinks.add(new TextLink( + start, end, new EntityConfidence(entityScores), extras, urlSpan)); return this; } diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java index f23691586a2a..4a6f3e53b223 100644 --- a/core/java/android/view/textclassifier/TextSelection.java +++ b/core/java/android/view/textclassifier/TextSelection.java @@ -24,10 +24,12 @@ import android.os.Bundle; import android.os.LocaleList; import android.os.Parcel; import android.os.Parcelable; +import android.text.SpannedString; import android.util.ArrayMap; import android.view.textclassifier.TextClassifier.EntityType; import android.view.textclassifier.TextClassifier.Utils; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.util.Locale; @@ -209,6 +211,7 @@ public final class TextSelection implements Parcelable { @Nullable private final LocaleList mDefaultLocales; private final boolean mDarkLaunchAllowed; private final Bundle mExtras; + @Nullable private String mCallingPackageName; private Request( CharSequence text, @@ -270,6 +273,26 @@ public final class TextSelection implements Parcelable { } /** + * Sets the name of the package that is sending this request. + * <p> + * Package-private for SystemTextClassifier's use. + * @hide + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void setCallingPackageName(@Nullable String callingPackageName) { + mCallingPackageName = callingPackageName; + } + + /** + * Returns the name of the package that sent this request. + * This returns {@code null} if no calling package name is set. + */ + @Nullable + public String getCallingPackageName() { + return mCallingPackageName; + } + + /** * Returns the extended data. * * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should @@ -355,7 +378,7 @@ public final class TextSelection implements Parcelable { */ @NonNull public Request build() { - return new Request(mText, mStartIndex, mEndIndex, + return new Request(new SpannedString(mText), mStartIndex, mEndIndex, mDefaultLocales, mDarkLaunchAllowed, mExtras == null ? Bundle.EMPTY : mExtras.deepCopy()); } @@ -368,21 +391,33 @@ public final class TextSelection implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mText.toString()); + dest.writeCharSequence(mText); dest.writeInt(mStartIndex); dest.writeInt(mEndIndex); - dest.writeInt(mDefaultLocales != null ? 1 : 0); - if (mDefaultLocales != null) { - mDefaultLocales.writeToParcel(dest, flags); - } + dest.writeParcelable(mDefaultLocales, flags); + dest.writeString(mCallingPackageName); dest.writeBundle(mExtras); } + private static Request readFromParcel(Parcel in) { + final CharSequence text = in.readCharSequence(); + final int startIndex = in.readInt(); + final int endIndex = in.readInt(); + final LocaleList defaultLocales = in.readParcelable(null); + final String callingPackageName = in.readString(); + final Bundle extras = in.readBundle(); + + final Request request = new Request(text, startIndex, endIndex, defaultLocales, + /* darkLaunchAllowed= */ false, extras); + request.setCallingPackageName(callingPackageName); + return request; + } + public static final Parcelable.Creator<Request> CREATOR = new Parcelable.Creator<Request>() { @Override public Request createFromParcel(Parcel in) { - return new Request(in); + return readFromParcel(in); } @Override @@ -390,15 +425,6 @@ public final class TextSelection implements Parcelable { return new Request[size]; } }; - - private Request(Parcel in) { - mText = in.readString(); - mStartIndex = in.readInt(); - mEndIndex = in.readInt(); - mDefaultLocales = in.readInt() == 0 ? null : LocaleList.CREATOR.createFromParcel(in); - mDarkLaunchAllowed = false; - mExtras = in.readBundle(); - } } @Override diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java index 91a54409608a..aaf7312fe0e6 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java @@ -189,6 +189,7 @@ public class TextClassificationTest { Instant.ofEpochMilli(946771200000L), // 2000-01-02 ZoneId.of("UTC")); final String text = "text"; + final String packageName = "packageName"; final TextClassification.Request reference = new TextClassification.Request.Builder(text, 0, text.length()) @@ -196,6 +197,7 @@ public class TextClassificationTest { .setReferenceTime(referenceTime) .setExtras(BUNDLE) .build(); + reference.setCallingPackageName(packageName); // Parcel and unparcel. final Parcel parcel = Parcel.obtain(); @@ -204,12 +206,13 @@ public class TextClassificationTest { final TextClassification.Request result = TextClassification.Request.CREATOR.createFromParcel(parcel); - assertEquals(text, result.getText()); + assertEquals(text, result.getText().toString()); assertEquals(0, result.getStartIndex()); assertEquals(text.length(), result.getEndIndex()); assertEquals(referenceTime, result.getReferenceTime()); assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags()); assertEquals(referenceTime, result.getReferenceTime()); assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY)); + assertEquals(packageName, result.getCallingPackageName()); } } diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java index 75ca769294ce..1dcaed6f6a1e 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java @@ -69,10 +69,12 @@ public final class TextLanguageTest { final String bundleKey = "experiment.str"; final Bundle bundle = new Bundle(); bundle.putString(bundleKey, "bundle"); + final String packageName = "packageName"; final TextLanguage.Request reference = new TextLanguage.Request.Builder(text) .setExtras(bundle) .build(); + reference.setCallingPackageName(packageName); final Parcel parcel = Parcel.obtain(); reference.writeToParcel(parcel, 0); @@ -81,5 +83,6 @@ public final class TextLanguageTest { assertEquals(text, result.getText()); assertEquals("bundle", result.getExtras().getString(bundleKey)); + assertEquals(packageName, result.getCallingPackageName()); } } diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java index f6ec0e6480f2..f022d040246b 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java @@ -64,7 +64,7 @@ public class TextLinksTest { public void testParcel() { final String fullText = "this is just a test"; final TextLinks reference = new TextLinks.Builder(fullText) - .addLink(0, 4, getEntityScores(0.f, 0.f, 1.f)) + .addLink(0, 4, getEntityScores(0.f, 0.f, 1.f), BUNDLE) .addLink(5, 12, getEntityScores(.8f, .1f, .5f)) .setExtras(BUNDLE) .build(); @@ -82,6 +82,7 @@ public class TextLinksTest { assertEquals(1, resultList.get(0).getEntityCount()); assertEquals(TextClassifier.TYPE_OTHER, resultList.get(0).getEntity(0)); assertEquals(1.f, resultList.get(0).getConfidenceScore(TextClassifier.TYPE_OTHER), 1e-7f); + assertEquals(BUNDLE_VALUE, resultList.get(0).getExtras().getString(BUNDLE_KEY)); assertEquals(5, resultList.get(1).getStart()); assertEquals(12, resultList.get(1).getEnd()); assertEquals(3, resultList.get(1).getEntityCount()); @@ -96,6 +97,7 @@ public class TextLinksTest { @Test public void testParcelOptions() { + final String packageName = "packageName"; final TextClassifier.EntityConfig entityConfig = TextClassifier.EntityConfig.create( Arrays.asList(TextClassifier.HINT_TEXT_IS_EDITABLE), Arrays.asList("a", "b", "c"), @@ -105,6 +107,7 @@ public class TextLinksTest { .setEntityConfig(entityConfig) .setExtras(BUNDLE) .build(); + reference.setCallingPackageName(packageName); // Parcel and unparcel. final Parcel parcel = Parcel.obtain(); @@ -119,5 +122,6 @@ public class TextLinksTest { assertEquals(new HashSet<String>(Arrays.asList("a", "c")), result.getEntityConfig().resolveEntityListModifications(Collections.emptyList())); assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY)); + assertEquals(packageName, result.getCallingPackageName()); } } diff --git a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java index 7ea5108bc3bb..2ea49f7d21be 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java @@ -75,11 +75,13 @@ public class TextSelectionTest { @Test public void testParcelRequest() { final String text = "text"; + final String packageName = "packageName"; final TextSelection.Request reference = new TextSelection.Request.Builder(text, 0, text.length()) .setDefaultLocales(new LocaleList(Locale.US, Locale.GERMANY)) .setExtras(BUNDLE) .build(); + reference.setCallingPackageName(packageName); // Parcel and unparcel. final Parcel parcel = Parcel.obtain(); @@ -87,10 +89,11 @@ public class TextSelectionTest { parcel.setDataPosition(0); final TextSelection.Request result = TextSelection.Request.CREATOR.createFromParcel(parcel); - assertEquals(text, result.getText()); + assertEquals(text, result.getText().toString()); assertEquals(0, result.getStartIndex()); assertEquals(text.length(), result.getEndIndex()); assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags()); assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY)); + assertEquals(packageName, result.getCallingPackageName()); } } diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java index c8a68b44c796..6b0419e0f7ad 100644 --- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java +++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java @@ -23,7 +23,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; -import android.content.pm.PackageManager; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; @@ -136,6 +135,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi throws RemoteException { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); + validateInput(mContext, request.getCallingPackageName()); synchronized (mLock) { UserState userState = getCallingUserStateLocked(); @@ -158,6 +158,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi throws RemoteException { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); + validateInput(mContext, request.getCallingPackageName()); synchronized (mLock) { UserState userState = getCallingUserStateLocked(); @@ -180,6 +181,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi throws RemoteException { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); + validateInput(mContext, request.getCallingPackageName()); synchronized (mLock) { UserState userState = getCallingUserStateLocked(); @@ -199,7 +201,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi public void onSelectionEvent( TextClassificationSessionId sessionId, SelectionEvent event) throws RemoteException { Preconditions.checkNotNull(event); - validateInput(event.getPackageName(), mContext); + validateInput(mContext, event.getPackageName()); synchronized (mLock) { UserState userState = getCallingUserStateLocked(); @@ -220,6 +222,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi ITextLanguageCallback callback) throws RemoteException { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); + validateInput(mContext, request.getCallingPackageName()); synchronized (mLock) { UserState userState = getCallingUserStateLocked(); @@ -242,6 +245,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi IConversationActionsCallback callback) throws RemoteException { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); + validateInput(mContext, request.getCallingPackageName()); synchronized (mLock) { UserState userState = getCallingUserStateLocked(); @@ -263,7 +267,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi throws RemoteException { Preconditions.checkNotNull(sessionId); Preconditions.checkNotNull(classificationContext); - validateInput(classificationContext.getPackageName(), mContext); + validateInput(mContext, classificationContext.getPackageName()); synchronized (mLock) { UserState userState = getCallingUserStateLocked(); @@ -398,15 +402,17 @@ public final class TextClassificationManagerService extends ITextClassifierServi e -> Slog.d(LOG_TAG, "Error " + opDesc + ": " + e.getMessage())); } - private static void validateInput(String packageName, Context context) + private static void validateInput(Context context, @Nullable String packageName) throws RemoteException { + if (packageName == null) return; + try { final int uid = context.getPackageManager() .getPackageUidAsUser(packageName, UserHandle.getCallingUserId()); Preconditions.checkArgument(Binder.getCallingUid() == uid); - } catch (IllegalArgumentException | NullPointerException | - PackageManager.NameNotFoundException e) { - throw new RemoteException(e.getMessage()); + } catch (Exception e) { + throw new RemoteException( + String.format("Invalid package: name=%s, error=%s", packageName, e)); } } |