diff --git a/api/current.txt b/api/current.txt index 0564de3f89cbc..28bf53b1a2563 100644 --- a/api/current.txt +++ b/api/current.txt @@ -52831,6 +52831,7 @@ package android.view.textclassifier { method public default int getMaxGenerateLinksTextLength(); method public default boolean isDestroyed(); method public default void onSelectionEvent(android.view.textclassifier.SelectionEvent); + method public default void onTextClassifierEvent(android.view.textclassifier.TextClassifierEvent); method public default android.view.textclassifier.ConversationActions suggestConversationActions(android.view.textclassifier.ConversationActions.Request); method public default android.view.textclassifier.TextSelection suggestSelection(android.view.textclassifier.TextSelection.Request); method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList); @@ -52852,6 +52853,7 @@ package android.view.textclassifier { field public static final java.lang.String WIDGET_TYPE_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview"; field public static final java.lang.String WIDGET_TYPE_EDITTEXT = "edittext"; field public static final java.lang.String WIDGET_TYPE_EDIT_WEBVIEW = "edit-webview"; + field public static final java.lang.String WIDGET_TYPE_NOTIFICATION = "notification"; field public static final java.lang.String WIDGET_TYPE_TEXTVIEW = "textview"; field public static final java.lang.String WIDGET_TYPE_UNKNOWN = "unknown"; field public static final java.lang.String WIDGET_TYPE_UNSELECTABLE_TEXTVIEW = "nosel-textview"; @@ -52869,6 +52871,68 @@ package android.view.textclassifier { field public static final android.os.Parcelable.Creator CREATOR; } + public final class TextClassifierEvent implements android.os.Parcelable { + method public int describeContents(); + method public int[] getActionIndices(); + method public java.lang.String getEntityType(); + method public int getEventCategory(); + method public android.view.textclassifier.TextClassificationContext getEventContext(); + method public int getEventIndex(); + method public long getEventTime(); + method public int getEventType(); + method public android.os.Bundle getExtras(); + method public java.lang.String getLanguage(); + method public int getRelativeSuggestedWordEndIndex(); + method public int getRelativeSuggestedWordStartIndex(); + method public int getRelativeWordEndIndex(); + method public int getRelativeWordStartIndex(); + method public java.lang.String getResultId(); + method public void writeToParcel(android.os.Parcel, int); + field public static final int CATEGORY_CONVERSATION_ACTIONS = 3; // 0x3 + field public static final int CATEGORY_LANGUAGE_DETECTION = 4; // 0x4 + field public static final int CATEGORY_LINKIFY = 2; // 0x2 + field public static final int CATEGORY_SELECTION = 1; // 0x1 + field public static final int CATEGORY_UNDEFINED = 0; // 0x0 + field public static final android.os.Parcelable.Creator CREATOR; + field public static final int TYPE_ACTIONS_SHOWN = 6; // 0x6 + field public static final int TYPE_AUTO_SELECTION = 5; // 0x5 + field public static final int TYPE_COPY_ACTION = 9; // 0x9 + field public static final int TYPE_CUT_ACTION = 11; // 0xb + field public static final int TYPE_LINK_CLICKED = 7; // 0x7 + field public static final int TYPE_MANUAL_REPLY = 19; // 0x13 + field public static final int TYPE_OTHER_ACTION = 16; // 0x10 + field public static final int TYPE_OVERTYPE = 8; // 0x8 + field public static final int TYPE_PASTE_ACTION = 10; // 0xa + field public static final int TYPE_SELECTION_DESTROYED = 15; // 0xf + field public static final int TYPE_SELECTION_DRAG = 14; // 0xe + field public static final int TYPE_SELECTION_MODIFIED = 2; // 0x2 + field public static final int TYPE_SELECTION_RESET = 18; // 0x12 + field public static final int TYPE_SELECTION_STARTED = 1; // 0x1 + field public static final int TYPE_SELECT_ALL = 17; // 0x11 + field public static final int TYPE_SHARE_ACTION = 12; // 0xc + field public static final int TYPE_SMART_ACTION = 13; // 0xd + field public static final int TYPE_SMART_SELECTION_MULTI = 4; // 0x4 + field public static final int TYPE_SMART_SELECTION_SINGLE = 3; // 0x3 + field public static final int TYPE_UNDEFINED = 0; // 0x0 + } + + public static final class TextClassifierEvent.Builder { + ctor public TextClassifierEvent.Builder(int, int); + method public android.view.textclassifier.TextClassifierEvent build(); + method public android.view.textclassifier.TextClassifierEvent.Builder setActionIndices(int...); + method public android.view.textclassifier.TextClassifierEvent.Builder setEntityType(java.lang.String); + method public android.view.textclassifier.TextClassifierEvent.Builder setEventContext(android.view.textclassifier.TextClassificationContext); + method public android.view.textclassifier.TextClassifierEvent.Builder setEventIndex(int); + method public android.view.textclassifier.TextClassifierEvent.Builder setEventTime(long); + method public android.view.textclassifier.TextClassifierEvent.Builder setExtras(android.os.Bundle); + method public android.view.textclassifier.TextClassifierEvent.Builder setLanguage(java.lang.String); + method public android.view.textclassifier.TextClassifierEvent.Builder setRelativeSuggestedWordEndIndex(int); + method public android.view.textclassifier.TextClassifierEvent.Builder setRelativeSuggestedWordStartIndex(int); + method public android.view.textclassifier.TextClassifierEvent.Builder setRelativeWordEndIndex(int); + method public android.view.textclassifier.TextClassifierEvent.Builder setRelativeWordStartIndex(int); + method public android.view.textclassifier.TextClassifierEvent.Builder setResultId(java.lang.String); + } + public final class TextLanguage implements android.os.Parcelable { method public int describeContents(); method public float getConfidenceScore(android.icu.util.ULocale); diff --git a/api/system-current.txt b/api/system-current.txt index 5a49f0bf33261..a2e5121a670bd 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5357,9 +5357,10 @@ package android.service.textclassifier { method public void onDestroyTextClassificationSession(android.view.textclassifier.TextClassificationSessionId); method public void onDetectLanguage(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.TextLanguage.Request, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback); method public abstract void onGenerateLinks(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.TextLinks.Request, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback); - method public void onSelectionEvent(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.SelectionEvent); + method public deprecated void onSelectionEvent(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.SelectionEvent); method public void onSuggestConversationActions(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.ConversationActions.Request, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback); method public abstract void onSuggestSelection(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.TextSelection.Request, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback); + method public void onTextClassifierEvent(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.TextClassifierEvent); field public static final java.lang.String SERVICE_INTERFACE = "android.service.textclassifier.TextClassifierService"; } diff --git a/core/java/android/service/textclassifier/ITextClassifierService.aidl b/core/java/android/service/textclassifier/ITextClassifierService.aidl index 254a710a2c408..794179415fc0b 100644 --- a/core/java/android/service/textclassifier/ITextClassifierService.aidl +++ b/core/java/android/service/textclassifier/ITextClassifierService.aidl @@ -26,6 +26,7 @@ import android.view.textclassifier.SelectionEvent; import android.view.textclassifier.TextClassification; import android.view.textclassifier.TextClassificationContext; import android.view.textclassifier.TextClassificationSessionId; +import android.view.textclassifier.TextClassifierEvent; import android.view.textclassifier.TextLinks; import android.view.textclassifier.TextLanguage; import android.view.textclassifier.TextSelection; @@ -52,10 +53,15 @@ oneway interface ITextClassifierService { in TextLinks.Request request, in ITextLinksCallback callback); + // TODO: Remove void onSelectionEvent( in TextClassificationSessionId sessionId, in SelectionEvent event); + void onTextClassifierEvent( + in TextClassificationSessionId sessionId, + in TextClassifierEvent event); + void onCreateTextClassificationSession( in TextClassificationContext context, in TextClassificationSessionId sessionId); diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java index 3b813c7df82b3..2221d6ec72961 100644 --- a/core/java/android/service/textclassifier/TextClassifierService.java +++ b/core/java/android/service/textclassifier/TextClassifierService.java @@ -39,6 +39,7 @@ import android.view.textclassifier.TextClassificationContext; import android.view.textclassifier.TextClassificationManager; import android.view.textclassifier.TextClassificationSessionId; import android.view.textclassifier.TextClassifier; +import android.view.textclassifier.TextClassifierEvent; import android.view.textclassifier.TextLanguage; import android.view.textclassifier.TextLinks; import android.view.textclassifier.TextSelection; @@ -191,6 +192,15 @@ public abstract class TextClassifierService extends Service { TextClassifierService.this.onSelectionEvent(sessionId, event); } + /** {@inheritDoc} */ + @Override + public void onTextClassifierEvent( + TextClassificationSessionId sessionId, + TextClassifierEvent event) { + Preconditions.checkNotNull(event); + TextClassifierService.this.onTextClassifierEvent(sessionId, event); + } + /** {@inheritDoc} */ @Override public void onDetectLanguage( @@ -368,10 +378,27 @@ public abstract class TextClassifierService extends Service { * * @param sessionId the session id * @param event the selection event + * @deprecated + * Use {@link #onTextClassifierEvent(TextClassificationSessionId, TextClassifierEvent)} + * instead */ + @Deprecated public void onSelectionEvent( @Nullable TextClassificationSessionId sessionId, @NonNull SelectionEvent event) {} + /** + * Writes the TextClassifier event. + * This is called when a TextClassifier event occurs. e.g. user changed selection, + * smart selection happened, or a link was clicked. + * + *

The default implementation ignores the event. + * + * @param sessionId the session id + * @param event the TextClassifier event + */ + public void onTextClassifierEvent( + @Nullable TextClassificationSessionId sessionId, @NonNull TextClassifierEvent event) {} + /** * Creates a new text classification session for the specified context. * diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java index c24489c8740b4..8b370f543cccf 100644 --- a/core/java/android/view/textclassifier/SystemTextClassifier.java +++ b/core/java/android/view/textclassifier/SystemTextClassifier.java @@ -146,6 +146,18 @@ public final class SystemTextClassifier implements TextClassifier { } } + @Override + public void onTextClassifierEvent(@NonNull TextClassifierEvent event) { + Preconditions.checkNotNull(event); + Utils.checkMainThread(); + + try { + mManagerService.onTextClassifierEvent(mSessionId, event); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Error reporting textclassifier event.", e); + } + } + @Override public TextLanguage detectLanguage(TextLanguage.Request request) { Preconditions.checkNotNull(request); diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java index e894ab44b88cd..8709e09bbf558 100644 --- a/core/java/android/view/textclassifier/TextClassifier.java +++ b/core/java/android/view/textclassifier/TextClassifier.java @@ -127,32 +127,34 @@ public interface TextClassifier { @StringDef({WIDGET_TYPE_TEXTVIEW, WIDGET_TYPE_EDITTEXT, WIDGET_TYPE_UNSELECTABLE_TEXTVIEW, WIDGET_TYPE_WEBVIEW, WIDGET_TYPE_EDIT_WEBVIEW, WIDGET_TYPE_CUSTOM_TEXTVIEW, WIDGET_TYPE_CUSTOM_EDITTEXT, WIDGET_TYPE_CUSTOM_UNSELECTABLE_TEXTVIEW, - WIDGET_TYPE_UNKNOWN}) + WIDGET_TYPE_NOTIFICATION, WIDGET_TYPE_UNKNOWN}) @interface WidgetType {} - /** The widget involved in the text classification session is a standard + /** The widget involved in the text classification context is a standard * {@link android.widget.TextView}. */ String WIDGET_TYPE_TEXTVIEW = "textview"; - /** The widget involved in the text classification session is a standard + /** The widget involved in the text classification context is a standard * {@link android.widget.EditText}. */ String WIDGET_TYPE_EDITTEXT = "edittext"; - /** The widget involved in the text classification session is a standard non-selectable + /** The widget involved in the text classification context is a standard non-selectable * {@link android.widget.TextView}. */ String WIDGET_TYPE_UNSELECTABLE_TEXTVIEW = "nosel-textview"; - /** The widget involved in the text classification session is a standard + /** The widget involved in the text classification context is a standard * {@link android.webkit.WebView}. */ String WIDGET_TYPE_WEBVIEW = "webview"; - /** The widget involved in the text classification session is a standard editable + /** The widget involved in the text classification context is a standard editable * {@link android.webkit.WebView}. */ String WIDGET_TYPE_EDIT_WEBVIEW = "edit-webview"; - /** The widget involved in the text classification session is a custom text widget. */ + /** The widget involved in the text classification context is a custom text widget. */ String WIDGET_TYPE_CUSTOM_TEXTVIEW = "customview"; - /** The widget involved in the text classification session is a custom editable text widget. */ + /** The widget involved in the text classification context is a custom editable text widget. */ String WIDGET_TYPE_CUSTOM_EDITTEXT = "customedit"; - /** The widget involved in the text classification session is a custom non-selectable text + /** The widget involved in the text classification context is a custom non-selectable text * widget. */ String WIDGET_TYPE_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview"; - /** The widget involved in the text classification session is of an unknown/unspecified type. */ + /** The widget involved in the text classification context is a notification */ + String WIDGET_TYPE_NOTIFICATION = "notification"; + /** The widget involved in the text classification context is of an unknown/unspecified type. */ String WIDGET_TYPE_UNKNOWN = "unknown"; /** @@ -353,12 +355,26 @@ public interface TextClassifier { } /** + * NOTE: Use {@link #onTextClassifierEvent(TextClassifierEvent)} instead. + *

* Reports a selection event. * *

NOTE: If a TextClassifier has been destroyed, calls to this method should * throw an {@link IllegalStateException}. See {@link #isDestroyed()}. */ - default void onSelectionEvent(@NonNull SelectionEvent event) {} + default void onSelectionEvent(@NonNull SelectionEvent event) { + // TODO: Consider rerouting to onTextClassifierEvent() + } + + /** + * Reports a text classifier event. + *

+ * NOTE: Call on a worker thread. + * + * @throws IllegalStateException if this TextClassifier has been destroyed. + * @see #isDestroyed() + */ + default void onTextClassifierEvent(@NonNull TextClassifierEvent event) {} /** * Destroys this TextClassifier. diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.aidl b/core/java/android/view/textclassifier/TextClassifierEvent.aidl new file mode 100644 index 0000000000000..86fa4f887de45 --- /dev/null +++ b/core/java/android/view/textclassifier/TextClassifierEvent.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.textclassifier; + +parcelable TextClassifierEvent; diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java new file mode 100644 index 0000000000000..3bb9ee88dae91 --- /dev/null +++ b/core/java/android/view/textclassifier/TextClassifierEvent.java @@ -0,0 +1,501 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.textclassifier; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A text classifier event. + */ +// TODO: Comprehensive javadoc. +public final class TextClassifierEvent implements Parcelable { + + public static final Creator CREATOR = new Creator() { + @Override + public TextClassifierEvent createFromParcel(Parcel in) { + return readFromParcel(in); + } + + @Override + public TextClassifierEvent[] newArray(int size) { + return new TextClassifierEvent[size]; + } + }; + + /** @hide **/ + @Retention(RetentionPolicy.SOURCE) + @IntDef({CATEGORY_UNDEFINED, CATEGORY_SELECTION, CATEGORY_LINKIFY, + CATEGORY_CONVERSATION_ACTIONS, CATEGORY_LANGUAGE_DETECTION}) + public @interface Category { + // For custom event categories, use range 1000+. + } + /** Undefined category */ + public static final int CATEGORY_UNDEFINED = 0; + /** Smart selection */ + public static final int CATEGORY_SELECTION = 1; + /** Linkify */ + public static final int CATEGORY_LINKIFY = 2; + /** Conversation actions */ + public static final int CATEGORY_CONVERSATION_ACTIONS = 3; + /** Language detection */ + public static final int CATEGORY_LANGUAGE_DETECTION = 4; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({TYPE_UNDEFINED, TYPE_SELECTION_STARTED, TYPE_SELECTION_MODIFIED, + TYPE_SMART_SELECTION_SINGLE, TYPE_SMART_SELECTION_MULTI, TYPE_AUTO_SELECTION, + TYPE_ACTIONS_SHOWN, TYPE_LINK_CLICKED, TYPE_OVERTYPE, TYPE_COPY_ACTION, + TYPE_PASTE_ACTION, TYPE_CUT_ACTION, TYPE_SHARE_ACTION, TYPE_SMART_ACTION, + TYPE_SELECTION_DRAG, TYPE_SELECTION_DESTROYED, TYPE_OTHER_ACTION, TYPE_SELECT_ALL, + TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY}) + public @interface Type { + // For custom event types, use range 1,000,000+. + } + /** User started a new selection. */ + public static final int TYPE_UNDEFINED = 0; + /** User started a new selection. */ + public static final int TYPE_SELECTION_STARTED = 1; + /** User modified an existing selection. */ + public static final int TYPE_SELECTION_MODIFIED = 2; + /** Smart selection triggered for a single token (word). */ + public static final int TYPE_SMART_SELECTION_SINGLE = 3; + /** Smart selection triggered spanning multiple tokens (words). */ + public static final int TYPE_SMART_SELECTION_MULTI = 4; + /** Something else other than user or the default TextClassifier triggered a selection. */ + public static final int TYPE_AUTO_SELECTION = 5; + /** Smart actions shown to the user. */ + public static final int TYPE_ACTIONS_SHOWN = 6; + /** User clicked a link. */ + public static final int TYPE_LINK_CLICKED = 7; + /** User typed over the selection. */ + public static final int TYPE_OVERTYPE = 8; + /** User clicked on Copy action. */ + public static final int TYPE_COPY_ACTION = 9; + /** User clicked on Paste action. */ + public static final int TYPE_PASTE_ACTION = 10; + /** User clicked on Cut action. */ + public static final int TYPE_CUT_ACTION = 11; + /** User clicked on Share action. */ + public static final int TYPE_SHARE_ACTION = 12; + /** User clicked on a Smart action. */ + public static final int TYPE_SMART_ACTION = 13; + /** User dragged+dropped the selection. */ + public static final int TYPE_SELECTION_DRAG = 14; + /** Selection is destroyed. */ + public static final int TYPE_SELECTION_DESTROYED = 15; + /** User clicked on a custom action. */ + public static final int TYPE_OTHER_ACTION = 16; + /** User clicked on Select All action */ + public static final int TYPE_SELECT_ALL = 17; + /** User reset the smart selection. */ + public static final int TYPE_SELECTION_RESET = 18; + /** User composed a reply. */ + public static final int TYPE_MANUAL_REPLY = 19; + + @Category private final int mEventCategory; + @Type private final int mEventType; + @Nullable private final String mEntityType; + @Nullable private final TextClassificationContext mEventContext; + @Nullable private final String mResultId; + private final int mEventIndex; + private final long mEventTime; + private final Bundle mExtras; + + // Smart selection. + private final int mRelativeWordStartIndex; + private final int mRelativeWordEndIndex; + private final int mRelativeSuggestedWordStartIndex; + private final int mRelativeSuggestedWordEndIndex; + + // Smart action. + private final int[] mActionIndices; + + // Language detection. + @Nullable private final String mLanguage; + + private TextClassifierEvent( + int eventCategory, + int eventType, + String entityType, + TextClassificationContext eventContext, + String resultId, + int eventIndex, + long eventTime, + Bundle extras, + int relativeWordStartIndex, + int relativeWordEndIndex, + int relativeSuggestedWordStartIndex, + int relativeSuggestedWordEndIndex, + int[] actionIndex, + String language) { + mEventCategory = eventCategory; + mEventType = eventType; + mEntityType = entityType; + mEventContext = eventContext; + mResultId = resultId; + mEventIndex = eventIndex; + mEventTime = eventTime; + mExtras = extras; + mRelativeWordStartIndex = relativeWordStartIndex; + mRelativeWordEndIndex = relativeWordEndIndex; + mRelativeSuggestedWordStartIndex = relativeSuggestedWordStartIndex; + mRelativeSuggestedWordEndIndex = relativeSuggestedWordEndIndex; + mActionIndices = actionIndex; + mLanguage = language; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mEventCategory); + dest.writeInt(mEventType); + dest.writeString(mEntityType); + dest.writeParcelable(mEventContext, flags); + dest.writeString(mResultId); + dest.writeInt(mEventIndex); + dest.writeLong(mEventTime); + dest.writeBundle(mExtras); + dest.writeInt(mRelativeWordStartIndex); + dest.writeInt(mRelativeWordEndIndex); + dest.writeInt(mRelativeSuggestedWordStartIndex); + dest.writeInt(mRelativeSuggestedWordEndIndex); + dest.writeIntArray(mActionIndices); + dest.writeString(mLanguage); + } + + private static TextClassifierEvent readFromParcel(Parcel in) { + return new TextClassifierEvent( + /* eventCategory= */ in.readInt(), + /* eventType= */ in.readInt(), + /* entityType= */ in.readString(), + /* eventContext= */ in.readParcelable(null), + /* resultId= */ in.readString(), + /* eventIndex= */ in.readInt(), + /* eventTime= */ in.readLong(), + /* extras= */ in.readBundle(), + /* relativeWordStartIndex= */ in.readInt(), + /* relativeWordEndIndex= */ in.readInt(), + /* relativeSuggestedWordStartIndex= */ in.readInt(), + /* relativeSuggestedWordEndIndex= */ in.readInt(), + /* actionIndices= */ in.createIntArray(), + /* language= */ in.readString()); + } + + /** + * Returns the event category. e.g. {@link #CATEGORY_SELECTION}. + */ + @Category + public int getEventCategory() { + return mEventCategory; + } + + /** + * Returns the event type. e.g. {@link #TYPE_SELECTION_STARTED}. + */ + @Type + public int getEventType() { + return mEventType; + } + + /** + * Returns the entity type. e.g. {@link TextClassifier#TYPE_ADDRESS}. + */ + @Nullable + public String getEntityType() { + return mEntityType; + } + + /** + * Returns the event context. + */ + @Nullable + public TextClassificationContext getEventContext() { + return mEventContext; + } + + /** + * Returns the id of the text classifier result related to this event. + */ + @Nullable + public String getResultId() { + return mResultId; + } + + /** + * Returns the index of this event in the series of event it belongs to. + */ + public int getEventIndex() { + return mEventIndex; + } + + /** + * Returns the time this event occurred. This is the number of milliseconds since + * January 1, 1970, 00:00:00 GMT. 0 indicates not set. + */ + public long getEventTime() { + return mEventTime; + } + + /** + * Returns a bundle containing non-structured extra information about this event. + * + *

NOTE: Do not modify this bundle. + */ + @NonNull + public Bundle getExtras() { + return mExtras; + } + + /** + * For smart selection. Returns the relative word index of the start of the selection. + */ + public int getRelativeWordStartIndex() { + return mRelativeWordStartIndex; + } + + /** + * For smart selection. Returns the relative word (exclusive) index of the end of the selection. + */ + public int getRelativeWordEndIndex() { + return mRelativeWordEndIndex; + } + + /** + * For smart selection. Returns the relative word index of the start of the smart selection. + */ + public int getRelativeSuggestedWordStartIndex() { + return mRelativeSuggestedWordStartIndex; + } + + /** + * For smart selection. Returns the relative word (exclusive) index of the end of the + * smart selection. + */ + public int getRelativeSuggestedWordEndIndex() { + return mRelativeSuggestedWordEndIndex; + } + + /** + * Returns the indices of the actions relating to this event. + * Actions are usually returned by the text classifier in priority order with the most + * preferred action at index 0. This list gives an indication of the position of the actions + * that are being reported. + */ + @NonNull + public int[] getActionIndices() { + return mActionIndices; + } + + /** + * For language detection. Returns the language tag for the detected locale. + * @see java.util.Locale#forLanguageTag(String). + */ + @Nullable + public String getLanguage() { + return mLanguage; + } + + /** + * Builder to build a text classifier event. + */ + public static final class Builder { + + private final int mEventCategory; + private final int mEventType; + @Nullable private String mEntityType; + @Nullable private TextClassificationContext mEventContext; + @Nullable private String mResultId; + private int mEventIndex; + private long mEventTime; + @Nullable private Bundle mExtras; + private int mRelativeWordStartIndex; + private int mRelativeWordEndIndex; + private int mRelativeSuggestedWordStartIndex; + private int mRelativeSuggestedWordEndIndex; + private int[] mActionIndices = new int[0]; + @Nullable private String mLanguage; + + /** + * Creates a builder for building {@link TextClassifierEvent}s. + * + * @param eventCategory The event category. e.g. {@link #CATEGORY_SELECTION} + * @param eventType The event type. e.g. {@link #TYPE_SELECTION_STARTED} + */ + public Builder(@Category int eventCategory, @Type int eventType) { + mEventCategory = eventCategory; + mEventType = eventType; + } + + /** + * Sets the entity type. e.g. {@link TextClassifier#TYPE_ADDRESS}. + */ + @NonNull + public Builder setEntityType(@Nullable String entityType) { + mEntityType = entityType; + return this; + } + + /** + * Sets the event context. + */ + @NonNull + public Builder setEventContext(@Nullable TextClassificationContext eventContext) { + mEventContext = eventContext; + return this; + } + + /** + * Sets the id of the text classifier result related to this event. + */ + @NonNull + public Builder setResultId(@Nullable String resultId) { + mResultId = resultId; + return this; + } + + /** + * Sets the index of this events in the series of events it belongs to. + */ + @NonNull + public Builder setEventIndex(int eventIndex) { + mEventIndex = eventIndex; + return this; + } + + /** + * Sets the time this event occurred. This is the number of milliseconds since + * January 1, 1970, 00:00:00 GMT. 0 indicates not set. + */ + @NonNull + public Builder setEventTime(long eventTime) { + mEventTime = eventTime; + return this; + } + + /** + * Sets a bundle containing non-structured extra information about the event. + * + *

NOTE: Prefer to set only immutable values on the bundle otherwise, avoid + * updating the internals of this bundle as it may have unexpected consequences on the + * clients of the built event object. For similar reasons, avoid depending on mutable + * objects in this bundle. + */ + @NonNull + public Builder setExtras(@NonNull Bundle extras) { + mExtras = Preconditions.checkNotNull(extras); + return this; + } + + /** + * For smart selection. Sets the relative word index of the start of the selection. + */ + @NonNull + public Builder setRelativeWordStartIndex(int relativeWordStartIndex) { + mRelativeWordStartIndex = relativeWordStartIndex; + return this; + } + + /** + * For smart selection. Sets the relative word (exclusive) index of the end of the + * selection. + */ + @NonNull + public Builder setRelativeWordEndIndex(int relativeWordEndIndex) { + mRelativeWordEndIndex = relativeWordEndIndex; + return this; + } + + /** + * For smart selection. Sets the relative word index of the start of the smart selection. + */ + @NonNull + public Builder setRelativeSuggestedWordStartIndex(int relativeSuggestedWordStartIndex) { + mRelativeSuggestedWordStartIndex = relativeSuggestedWordStartIndex; + return this; + } + + /** + * For smart selection. Sets the relative word (exclusive) index of the end of the + * smart selection. + */ + @NonNull + public Builder setRelativeSuggestedWordEndIndex(int relativeSuggestedWordEndIndex) { + mRelativeSuggestedWordEndIndex = relativeSuggestedWordEndIndex; + return this; + } + + /** + * Sets the indices of the actions involved in this event. Actions are usually returned by + * the text classifier in priority order with the most preferred action at index 0. + * This index gives an indication of the position of the action that is being reported. + */ + @NonNull + public Builder setActionIndices(@NonNull int... actionIndices) { + mActionIndices = new int[actionIndices.length]; + System.arraycopy(actionIndices, 0, mActionIndices, 0, actionIndices.length); + return this; + } + + /** + * For language detection. Sets the language tag for the detected locale. + * @see java.util.Locale#forLanguageTag(String). + */ + @NonNull + public Builder setLanguage(@Nullable String language) { + mLanguage = language; + return this; + } + + /** + * Builds and returns a text classifier event. + */ + @NonNull + public TextClassifierEvent build() { + mExtras = mExtras == null ? Bundle.EMPTY : mExtras; + return new TextClassifierEvent( + mEventCategory, + mEventType, + mEntityType, + mEventContext, + mResultId, + mEventIndex, + mEventTime, + mExtras, + mRelativeWordStartIndex, + mRelativeWordEndIndex, + mRelativeSuggestedWordStartIndex, + mRelativeSuggestedWordEndIndex, + mActionIndices, + mLanguage); + } + // TODO: Add build(boolean validate). + } +} diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java index df38e2ee79118..9b0f9c6ee5e85 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -341,6 +341,11 @@ public final class TextClassifierImpl implements TextClassifier { } } + @Override + public void onTextClassifierEvent(@NonNull TextClassifierEvent event) { + // TODO: Implement. + } + /** @inheritDoc */ @Override public TextLanguage detectLanguage(@NonNull TextLanguage.Request request) { diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java index 6b0419e0f7adf..2cab63aa680a1 100644 --- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java +++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java @@ -42,6 +42,7 @@ import android.view.textclassifier.TextClassification; import android.view.textclassifier.TextClassificationContext; import android.view.textclassifier.TextClassificationManager; import android.view.textclassifier.TextClassificationSessionId; +import android.view.textclassifier.TextClassifierEvent; import android.view.textclassifier.TextLanguage; import android.view.textclassifier.TextLinks; import android.view.textclassifier.TextSelection; @@ -214,6 +215,27 @@ public final class TextClassificationManagerService extends ITextClassifierServi } } } + @Override + public void onTextClassifierEvent( + TextClassificationSessionId sessionId, + TextClassifierEvent event) throws RemoteException { + Preconditions.checkNotNull(event); + final String packageName = event.getEventContext() == null + ? null + : event.getEventContext().getPackageName(); + validateInput(mContext, packageName); + + synchronized (mLock) { + UserState userState = getCallingUserStateLocked(); + if (userState.isBoundLocked()) { + userState.mService.onTextClassifierEvent(sessionId, event); + } else { + userState.mPendingRequests.add(new PendingRequest( + () -> onTextClassifierEvent(sessionId, event), + null /* onServiceFailure */, null /* binder */, this, userState)); + } + } + } @Override public void onDetectLanguage(