1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.textclassifier.common.logging;
18 
19 import android.os.Bundle;
20 import androidx.annotation.IntDef;
21 import com.google.common.base.Preconditions;
22 import java.lang.annotation.Retention;
23 import java.lang.annotation.RetentionPolicy;
24 import java.util.Arrays;
25 import java.util.Locale;
26 import javax.annotation.Nonnull;
27 import javax.annotation.Nullable;
28 
29 /**
30  * This class represents events that are sent by components to a TextClassifier to report something
31  * of note that relates to a feature powered by the TextClassifier. The TextClassifier may log these
32  * events or use them to improve future responses to queries.
33  *
34  * <p>Each category of events has its their own subclass. Events of each type have an associated set
35  * of related properties. You can find their specification in the subclasses.
36  */
37 public abstract class TextClassifierEvent {
38 
39   /** Category of the event */
40   @Retention(RetentionPolicy.SOURCE)
41   @IntDef({
42     CATEGORY_SELECTION,
43     CATEGORY_LINKIFY,
44     CATEGORY_CONVERSATION_ACTIONS,
45     CATEGORY_LANGUAGE_DETECTION
46   })
47   public @interface Category {
48     // For custom event categories, use range 1000+.
49   }
50 
51   /**
52    * Smart selection
53    *
54    * @see TextSelectionEvent
55    */
56   public static final int CATEGORY_SELECTION = 1;
57   /**
58    * Linkify
59    *
60    * @see TextLinkifyEvent
61    */
62   public static final int CATEGORY_LINKIFY = 2;
63   /**
64    * Conversation actions
65    *
66    * @see ConversationActionsEvent
67    */
68   public static final int CATEGORY_CONVERSATION_ACTIONS = 3;
69   /**
70    * Language detection
71    *
72    * @see LanguageDetectionEvent
73    */
74   public static final int CATEGORY_LANGUAGE_DETECTION = 4;
75 
76   /** Type of the event */
77   @Retention(RetentionPolicy.SOURCE)
78   @IntDef({
79     TYPE_SELECTION_STARTED,
80     TYPE_SELECTION_MODIFIED,
81     TYPE_SMART_SELECTION_SINGLE,
82     TYPE_SMART_SELECTION_MULTI,
83     TYPE_AUTO_SELECTION,
84     TYPE_ACTIONS_SHOWN,
85     TYPE_LINK_CLICKED,
86     TYPE_OVERTYPE,
87     TYPE_COPY_ACTION,
88     TYPE_PASTE_ACTION,
89     TYPE_CUT_ACTION,
90     TYPE_SHARE_ACTION,
91     TYPE_SMART_ACTION,
92     TYPE_SELECTION_DRAG,
93     TYPE_SELECTION_DESTROYED,
94     TYPE_OTHER_ACTION,
95     TYPE_SELECT_ALL,
96     TYPE_SELECTION_RESET,
97     TYPE_MANUAL_REPLY,
98     TYPE_ACTIONS_GENERATED,
99     TYPE_LINKS_GENERATED
100   })
101   public @interface Type {
102     // For custom event types, use range 1,000,000+.
103   }
104 
105   // All these event type constants are required to match with those defined in
106   // textclassifier_enums.proto.
107   /** User started a new selection. */
108   public static final int TYPE_SELECTION_STARTED = 1;
109   /** User modified an existing selection. */
110   public static final int TYPE_SELECTION_MODIFIED = 2;
111   /** Smart selection triggered for a single token (word). */
112   public static final int TYPE_SMART_SELECTION_SINGLE = 3;
113   /** Smart selection triggered spanning multiple tokens (words). */
114   public static final int TYPE_SMART_SELECTION_MULTI = 4;
115   /** Something else other than user or the default TextClassifier triggered a selection. */
116   public static final int TYPE_AUTO_SELECTION = 5;
117   /** Smart actions shown to the user. */
118   public static final int TYPE_ACTIONS_SHOWN = 6;
119   /** User clicked a link. */
120   public static final int TYPE_LINK_CLICKED = 7;
121   /** User typed over the selection. */
122   public static final int TYPE_OVERTYPE = 8;
123   /** User clicked on Copy action. */
124   public static final int TYPE_COPY_ACTION = 9;
125   /** User clicked on Paste action. */
126   public static final int TYPE_PASTE_ACTION = 10;
127   /** User clicked on Cut action. */
128   public static final int TYPE_CUT_ACTION = 11;
129   /** User clicked on Share action. */
130   public static final int TYPE_SHARE_ACTION = 12;
131   /** User clicked on a Smart action. */
132   public static final int TYPE_SMART_ACTION = 13;
133   /** User dragged+dropped the selection. */
134   public static final int TYPE_SELECTION_DRAG = 14;
135   /** Selection is destroyed. */
136   public static final int TYPE_SELECTION_DESTROYED = 15;
137   /** User clicked on a custom action. */
138   public static final int TYPE_OTHER_ACTION = 16;
139   /** User clicked on Select All action */
140   public static final int TYPE_SELECT_ALL = 17;
141   /** User reset the smart selection. */
142   public static final int TYPE_SELECTION_RESET = 18;
143   /** User composed a reply. */
144   public static final int TYPE_MANUAL_REPLY = 19;
145   /** TextClassifier generated some actions */
146   public static final int TYPE_ACTIONS_GENERATED = 20;
147   /** Some text links were generated. */
148   public static final int TYPE_LINKS_GENERATED = 21;
149 
150   @Category private final int eventCategory;
151   @Type private final int eventType;
152   @Nullable private final String[] entityTypes;
153   @Nullable private TextClassificationContext eventContext;
154   @Nullable private final String resultId;
155   private final int eventIndex;
156   private final float[] scores;
157   @Nullable private final String modelName;
158   private final int[] actionIndices;
159   @Nullable private final Locale locale;
160   private final Bundle extras;
161 
TextClassifierEvent(Builder<?> builder)162   private TextClassifierEvent(Builder<?> builder) {
163     eventCategory = builder.eventCategory;
164     eventType = builder.eventType;
165     entityTypes = builder.entityTypes;
166     eventContext = builder.eventContext;
167     resultId = builder.resultId;
168     eventIndex = builder.eventIndex;
169     scores = builder.scores;
170     modelName = builder.modelName;
171     actionIndices = builder.actionIndices;
172     locale = builder.locale;
173     extras = builder.extras == null ? Bundle.EMPTY : builder.extras;
174   }
175 
176   /** Returns the event category. e.g. {@link #CATEGORY_SELECTION}. */
177   @Category
getEventCategory()178   public int getEventCategory() {
179     return eventCategory;
180   }
181 
182   /** Returns the event type. e.g. {@link #TYPE_SELECTION_STARTED}. */
183   @Type
getEventType()184   public int getEventType() {
185     return eventType;
186   }
187 
188   /**
189    * Returns an array of entity types. e.g. {@link TextClassifier#TYPE_ADDRESS}.
190    *
191    * @see Builder#setEntityTypes(String...) for supported types.
192    */
193   @Nonnull
getEntityTypes()194   public String[] getEntityTypes() {
195     return entityTypes;
196   }
197 
198   /** Returns the event context. */
199   @Nullable
getEventContext()200   public TextClassificationContext getEventContext() {
201     return eventContext;
202   }
203 
204   /**
205    * Sets the event context.
206    *
207    * <p>Package-private for SystemTextClassifier's use.
208    */
setEventContext(@ullable TextClassificationContext eventContext)209   void setEventContext(@Nullable TextClassificationContext eventContext) {
210     this.eventContext = eventContext;
211   }
212 
213   /** Returns the id of the text classifier result related to this event. */
214   @Nullable
getResultId()215   public String getResultId() {
216     return resultId;
217   }
218 
219   /** Returns the index of this event in the series of event it belongs to. */
getEventIndex()220   public int getEventIndex() {
221     return eventIndex;
222   }
223 
224   /** Returns the scores of the suggestions. */
getScores()225   public float[] getScores() {
226     return scores;
227   }
228 
229   /** Returns the model name. */
230   @Nullable
getModelName()231   public String getModelName() {
232     return modelName;
233   }
234 
235   /**
236    * Returns the indices of the actions relating to this event. Actions are usually returned by the
237    * text classifier in priority order with the most preferred action at index 0. This list gives an
238    * indication of the position of the actions that are being reported.
239    *
240    * @see Builder#setActionIndices(int...)
241    */
getActionIndices()242   public int[] getActionIndices() {
243     return actionIndices;
244   }
245 
246   /** Returns the detected locale. */
247   @Nullable
getLocale()248   public Locale getLocale() {
249     return locale;
250   }
251 
252   /**
253    * Returns a bundle containing non-structured extra information about this event.
254    *
255    * <p><b>NOTE: </b>Do not modify this bundle.
256    */
257   @Nonnull
getExtras()258   public Bundle getExtras() {
259     return extras;
260   }
261 
262   @Override
toString()263   public String toString() {
264     StringBuilder out = new StringBuilder(128);
265     out.append(this.getClass().getSimpleName());
266     out.append("{");
267     out.append("mEventCategory=").append(eventCategory);
268     out.append(", mEventType=").append(eventType);
269     out.append(", mEntityTypes=").append(Arrays.toString(entityTypes));
270     out.append(", mEventContext=").append(eventContext);
271     out.append(", mResultId=").append(resultId);
272     out.append(", mEventIndex=").append(eventIndex);
273     out.append(", mExtras=").append(extras);
274     out.append(", mScores=").append(Arrays.toString(scores));
275     out.append(", mModelName=").append(modelName);
276     out.append(", mActionIndices=").append(Arrays.toString(actionIndices));
277     toString(out);
278     out.append("}");
279     return out.toString();
280   }
281 
282   /**
283    * Overrides this to append extra fields to the output of {@link #toString()}.
284    *
285    * <p>Extra fields should be formatted like this: ", {field_name}={field_value}".
286    */
toString(StringBuilder out)287   void toString(StringBuilder out) {}
288 
289   /**
290    * Builder to build a text classifier event.
291    *
292    * @param <T> The subclass to be built.
293    */
294   public abstract static class Builder<T extends Builder<T>> {
295 
296     private final int eventCategory;
297     private final int eventType;
298     private String[] entityTypes = new String[0];
299     @Nullable private TextClassificationContext eventContext;
300     @Nullable private String resultId;
301     private int eventIndex;
302     private float[] scores = new float[0];
303     @Nullable private String modelName;
304     private int[] actionIndices = new int[0];
305     @Nullable private Locale locale;
306     @Nullable private Bundle extras;
307 
308     /**
309      * Creates a builder for building {@link TextClassifierEvent}s.
310      *
311      * @param eventCategory The event category. e.g. {@link #CATEGORY_SELECTION}
312      * @param eventType The event type. e.g. {@link #TYPE_SELECTION_STARTED}
313      */
Builder(@ategory int eventCategory, @Type int eventType)314     private Builder(@Category int eventCategory, @Type int eventType) {
315       this.eventCategory = eventCategory;
316       this.eventType = eventType;
317     }
318 
319     /**
320      * Sets the entity types. e.g. {@link android.view.textclassifier.TextClassifier#TYPE_ADDRESS}.
321      *
322      * <p>Supported types:
323      *
324      * <p>See {@link android.view.textclassifier.TextClassifier.EntityType}
325      *
326      * <p>See {@link android.view.textclassifier.ConversationAction.ActionType}
327      *
328      * <p>See {@link Locale#toLanguageTag()}
329      */
setEntityTypes(String... entityTypes)330     public T setEntityTypes(String... entityTypes) {
331       Preconditions.checkNotNull(entityTypes);
332       this.entityTypes = new String[entityTypes.length];
333       System.arraycopy(entityTypes, 0, this.entityTypes, 0, entityTypes.length);
334       return self();
335     }
336 
337     /** Sets the event context. */
setEventContext(@ullable TextClassificationContext eventContext)338     public T setEventContext(@Nullable TextClassificationContext eventContext) {
339       this.eventContext = eventContext;
340       return self();
341     }
342 
343     /** Sets the id of the text classifier result related to this event. */
344     @Nonnull
setResultId(@ullable String resultId)345     public T setResultId(@Nullable String resultId) {
346       this.resultId = resultId;
347       return self();
348     }
349 
350     /** Sets the index of this event in the series of events it belongs to. */
351     @Nonnull
setEventIndex(int eventIndex)352     public T setEventIndex(int eventIndex) {
353       this.eventIndex = eventIndex;
354       return self();
355     }
356 
357     /** Sets the scores of the suggestions. */
358     @Nonnull
setScores(@onnull float... scores)359     public T setScores(@Nonnull float... scores) {
360       Preconditions.checkNotNull(scores);
361       this.scores = new float[scores.length];
362       System.arraycopy(scores, 0, this.scores, 0, scores.length);
363       return self();
364     }
365 
366     /** Sets the model name string. */
367     @Nonnull
setModelName(@ullable String modelVersion)368     public T setModelName(@Nullable String modelVersion) {
369       modelName = modelVersion;
370       return self();
371     }
372 
373     /**
374      * Sets the indices of the actions involved in this event. Actions are usually returned by the
375      * text classifier in priority order with the most preferred action at index 0. These indices
376      * give an indication of the position of the actions that are being reported.
377      *
378      * <p>E.g.
379      *
380      * <pre>
381      *   // 3 smart actions are shown at index 0, 1, 2 respectively in response to a link click.
382      *   new TextClassifierEvent.Builder(CATEGORY_LINKIFY, TYPE_ACTIONS_SHOWN)
383      *       .setEventIndex(0, 1, 2)
384      *       ...
385      *       .build();
386      *
387      *   ...
388      *
389      *   // Smart action at index 1 is activated.
390      *   new TextClassifierEvent.Builder(CATEGORY_LINKIFY, TYPE_SMART_ACTION)
391      *       .setEventIndex(1)
392      *       ...
393      *       .build();
394      * </pre>
395      *
396      * @see android.view.textclassifier.TextClassification#getActions()
397      */
398     @Nonnull
setActionIndices(@onnull int... actionIndices)399     public T setActionIndices(@Nonnull int... actionIndices) {
400       this.actionIndices = new int[actionIndices.length];
401       System.arraycopy(actionIndices, 0, this.actionIndices, 0, actionIndices.length);
402       return self();
403     }
404 
405     /** Sets the detected locale. */
406     @Nonnull
setLocale(@ullable Locale locale)407     public T setLocale(@Nullable Locale locale) {
408       this.locale = locale;
409       return self();
410     }
411 
412     /**
413      * Sets a bundle containing non-structured extra information about the event.
414      *
415      * <p><b>NOTE: </b>Prefer to set only immutable values on the bundle otherwise, avoid updating
416      * the internals of this bundle as it may have unexpected consequences on the clients of the
417      * built event object. For similar reasons, avoid depending on mutable objects in this bundle.
418      */
419     @Nonnull
setExtras(@onnull Bundle extras)420     public T setExtras(@Nonnull Bundle extras) {
421       this.extras = Preconditions.checkNotNull(extras);
422       return self();
423     }
424 
self()425     abstract T self();
426   }
427 
428   /**
429    * This class represents events that are related to the smart text selection feature.
430    *
431    * <p>
432    *
433    * <pre>
434    *     // User started a selection. e.g. "York" in text "New York City, NY".
435    *     new TextSelectionEvent.Builder(TYPE_SELECTION_STARTED)
436    *         .setEventContext(classificationContext)
437    *         .setEventIndex(0)
438    *         .build();
439    *
440    *     // System smart-selects a recognized entity. e.g. "New York City".
441    *     new TextSelectionEvent.Builder(TYPE_SMART_SELECTION_MULTI)
442    *         .setEventContext(classificationContext)
443    *         .setResultId(textSelection.getId())
444    *         .setRelativeWordStartIndex(-1) // Goes back one word to "New" from "York".
445    *         .setRelativeWordEndIndex(2)    // Goes forward 2 words from "York" to start of ",".
446    *         .setEntityTypes(textClassification.getEntity(0))
447    *         .setScore(textClassification.getConfidenceScore(entityType))
448    *         .setEventIndex(1)
449    *         .build();
450    *
451    *     // User resets the selection to the original selection. i.e. "York".
452    *     new TextSelectionEvent.Builder(TYPE_SELECTION_RESET)
453    *         .setEventContext(classificationContext)
454    *         .setResultId(textSelection.getId())
455    *         .setRelativeSuggestedWordStartIndex(-1) // Repeated from above.
456    *         .setRelativeSuggestedWordEndIndex(2)    // Repeated from above.
457    *         .setRelativeWordStartIndex(0)           // Original selection is always at (0, 1].
458    *         .setRelativeWordEndIndex(1)
459    *         .setEntityTypes(textClassification.getEntity(0))
460    *         .setScore(textClassification.getConfidenceScore(entityType))
461    *         .setEventIndex(2)
462    *         .build();
463    *
464    *     // User modified the selection. e.g. "New".
465    *     new TextSelectionEvent.Builder(TYPE_SELECTION_MODIFIED)
466    *         .setEventContext(classificationContext)
467    *         .setResultId(textSelection.getId())
468    *         .setRelativeSuggestedWordStartIndex(-1) // Repeated from above.
469    *         .setRelativeSuggestedWordEndIndex(2)    // Repeated from above.
470    *         .setRelativeWordStartIndex(-1)          // Goes backward one word from "York" to
471    *         "New".
472    *         .setRelativeWordEndIndex(0)             // Goes backward one word to exclude "York".
473    *         .setEntityTypes(textClassification.getEntity(0))
474    *         .setScore(textClassification.getConfidenceScore(entityType))
475    *         .setEventIndex(3)
476    *         .build();
477    *
478    *     // Smart (contextual) actions (at indices, 0, 1, 2) presented to the user.
479    *     // e.g. "Map", "Ride share", "Explore".
480    *     new TextSelectionEvent.Builder(TYPE_ACTIONS_SHOWN)
481    *         .setEventContext(classificationContext)
482    *         .setResultId(textClassification.getId())
483    *         .setEntityTypes(textClassification.getEntity(0))
484    *         .setScore(textClassification.getConfidenceScore(entityType))
485    *         .setActionIndices(0, 1, 2)
486    *         .setEventIndex(4)
487    *         .build();
488    *
489    *     // User chooses the "Copy" action.
490    *     new TextSelectionEvent.Builder(TYPE_COPY_ACTION)
491    *         .setEventContext(classificationContext)
492    *         .setResultId(textClassification.getId())
493    *         .setEntityTypes(textClassification.getEntity(0))
494    *         .setScore(textClassification.getConfidenceScore(entityType))
495    *         .setEventIndex(5)
496    *         .build();
497    *
498    *     // User chooses smart action at index 1. i.e. "Ride share".
499    *     new TextSelectionEvent.Builder(TYPE_SMART_ACTION)
500    *         .setEventContext(classificationContext)
501    *         .setResultId(textClassification.getId())
502    *         .setEntityTypes(textClassification.getEntity(0))
503    *         .setScore(textClassification.getConfidenceScore(entityType))
504    *         .setActionIndices(1)
505    *         .setEventIndex(5)
506    *         .build();
507    *
508    *     // Selection dismissed.
509    *     new TextSelectionEvent.Builder(TYPE_SELECTION_DESTROYED)
510    *         .setEventContext(classificationContext)
511    *         .setResultId(textClassification.getId())
512    *         .setEntityTypes(textClassification.getEntity(0))
513    *         .setScore(textClassification.getConfidenceScore(entityType))
514    *         .setEventIndex(6)
515    *         .build();
516    * </pre>
517    *
518    * <p>
519    */
520   public static final class TextSelectionEvent extends TextClassifierEvent {
521 
522     final int relativeWordStartIndex;
523     final int relativeWordEndIndex;
524     final int relativeSuggestedWordStartIndex;
525     final int relativeSuggestedWordEndIndex;
526 
TextSelectionEvent(TextSelectionEvent.Builder builder)527     private TextSelectionEvent(TextSelectionEvent.Builder builder) {
528       super(builder);
529       relativeWordStartIndex = builder.relativeWordStartIndex;
530       relativeWordEndIndex = builder.relativeWordEndIndex;
531       relativeSuggestedWordStartIndex = builder.relativeSuggestedWordStartIndex;
532       relativeSuggestedWordEndIndex = builder.relativeSuggestedWordEndIndex;
533     }
534 
535     /** Returns the relative word index of the start of the selection. */
getRelativeWordStartIndex()536     public int getRelativeWordStartIndex() {
537       return relativeWordStartIndex;
538     }
539 
540     /** Returns the relative word (exclusive) index of the end of the selection. */
getRelativeWordEndIndex()541     public int getRelativeWordEndIndex() {
542       return relativeWordEndIndex;
543     }
544 
545     /** Returns the relative word index of the start of the smart selection. */
getRelativeSuggestedWordStartIndex()546     public int getRelativeSuggestedWordStartIndex() {
547       return relativeSuggestedWordStartIndex;
548     }
549 
550     /** Returns the relative word (exclusive) index of the end of the smart selection. */
getRelativeSuggestedWordEndIndex()551     public int getRelativeSuggestedWordEndIndex() {
552       return relativeSuggestedWordEndIndex;
553     }
554 
555     @Override
toString(StringBuilder out)556     void toString(StringBuilder out) {
557       out.append(", getRelativeWordStartIndex=").append(relativeWordStartIndex);
558       out.append(", getRelativeWordEndIndex=").append(relativeWordEndIndex);
559       out.append(", getRelativeSuggestedWordStartIndex=").append(relativeSuggestedWordStartIndex);
560       out.append(", getRelativeSuggestedWordEndIndex=").append(relativeSuggestedWordEndIndex);
561     }
562 
563     /** Builder class for {@link TextSelectionEvent}. */
564     public static final class Builder
565         extends TextClassifierEvent.Builder<TextSelectionEvent.Builder> {
566       int relativeWordStartIndex;
567       int relativeWordEndIndex;
568       int relativeSuggestedWordStartIndex;
569       int relativeSuggestedWordEndIndex;
570 
571       /**
572        * Creates a builder for building {@link TextSelectionEvent}s.
573        *
574        * @param eventType The event type. e.g. {@link #TYPE_SELECTION_STARTED}
575        */
Builder(@ype int eventType)576       public Builder(@Type int eventType) {
577         super(CATEGORY_SELECTION, eventType);
578       }
579 
580       /** Sets the relative word index of the start of the selection. */
581       @Nonnull
setRelativeWordStartIndex(int relativeWordStartIndex)582       public Builder setRelativeWordStartIndex(int relativeWordStartIndex) {
583         this.relativeWordStartIndex = relativeWordStartIndex;
584         return this;
585       }
586 
587       /** Sets the relative word (exclusive) index of the end of the selection. */
588       @Nonnull
setRelativeWordEndIndex(int relativeWordEndIndex)589       public Builder setRelativeWordEndIndex(int relativeWordEndIndex) {
590         this.relativeWordEndIndex = relativeWordEndIndex;
591         return this;
592       }
593 
594       /** Sets the relative word index of the start of the smart selection. */
595       @Nonnull
setRelativeSuggestedWordStartIndex(int relativeSuggestedWordStartIndex)596       public Builder setRelativeSuggestedWordStartIndex(int relativeSuggestedWordStartIndex) {
597         this.relativeSuggestedWordStartIndex = relativeSuggestedWordStartIndex;
598         return this;
599       }
600 
601       /** Sets the relative word (exclusive) index of the end of the smart selection. */
602       @Nonnull
setRelativeSuggestedWordEndIndex(int relativeSuggestedWordEndIndex)603       public Builder setRelativeSuggestedWordEndIndex(int relativeSuggestedWordEndIndex) {
604         this.relativeSuggestedWordEndIndex = relativeSuggestedWordEndIndex;
605         return this;
606       }
607 
608       @Override
self()609       TextSelectionEvent.Builder self() {
610         return this;
611       }
612 
613       /** Builds and returns a {@link TextSelectionEvent}. */
614       @Nonnull
build()615       public TextSelectionEvent build() {
616         return new TextSelectionEvent(this);
617       }
618     }
619   }
620 
621   /**
622    * This class represents events that are related to the smart linkify feature.
623    *
624    * <p>
625    *
626    * <pre>
627    *     // User clicked on a link.
628    *     new TextLinkifyEvent.Builder(TYPE_LINK_CLICKED)
629    *         .setEventContext(classificationContext)
630    *         .setResultId(textClassification.getId())
631    *         .setEntityTypes(textClassification.getEntity(0))
632    *         .setScore(textClassification.getConfidenceScore(entityType))
633    *         .setEventIndex(0)
634    *         .build();
635    *
636    *     // Smart (contextual) actions presented to the user in response to a link click.
637    *     new TextLinkifyEvent.Builder(TYPE_ACTIONS_SHOWN)
638    *         .setEventContext(classificationContext)
639    *         .setResultId(textClassification.getId())
640    *         .setEntityTypes(textClassification.getEntity(0))
641    *         .setScore(textClassification.getConfidenceScore(entityType))
642    *         .setActionIndices(range(textClassification.getActions().size()))
643    *         .setEventIndex(1)
644    *         .build();
645    *
646    *     // User chooses smart action at index 0.
647    *     new TextLinkifyEvent.Builder(TYPE_SMART_ACTION)
648    *         .setEventContext(classificationContext)
649    *         .setResultId(textClassification.getId())
650    *         .setEntityTypes(textClassification.getEntity(0))
651    *         .setScore(textClassification.getConfidenceScore(entityType))
652    *         .setActionIndices(0)
653    *         .setEventIndex(2)
654    *         .build();
655    * </pre>
656    */
657   public static final class TextLinkifyEvent extends TextClassifierEvent {
658 
TextLinkifyEvent(TextLinkifyEvent.Builder builder)659     private TextLinkifyEvent(TextLinkifyEvent.Builder builder) {
660       super(builder);
661     }
662 
663     /** Builder class for {@link TextLinkifyEvent}. */
664     public static final class Builder
665         extends TextClassifierEvent.Builder<TextLinkifyEvent.Builder> {
666       /**
667        * Creates a builder for building {@link TextLinkifyEvent}s.
668        *
669        * @param eventType The event type. e.g. {@link #TYPE_SMART_ACTION}
670        */
Builder(@ype int eventType)671       public Builder(@Type int eventType) {
672         super(TextClassifierEvent.CATEGORY_LINKIFY, eventType);
673       }
674 
675       @Override
self()676       Builder self() {
677         return this;
678       }
679 
680       /** Builds and returns a {@link TextLinkifyEvent}. */
681       @Nonnull
build()682       public TextLinkifyEvent build() {
683         return new TextLinkifyEvent(this);
684       }
685     }
686   }
687 
688   /**
689    * This class represents events that are related to the language detection feature.
690    * <p>
691    * <pre>
692    *     // Translate action shown for foreign text.
693    *     new LanguageDetectionEvent.Builder(TYPE_ACTIONS_SHOWN)
694    *         .setEventContext(classificationContext)
695    *         .setResultId(textClassification.getId())
696    *         .setEntityTypes(language)
697    *         .setScore(score)
698    *         .setActionIndices(textClassification.getActions().indexOf(translateAction))
699    *         .setEventIndex(0)
700    *         .build();
701    *
702    *     // Translate action selected.
703    *     new LanguageDetectionEvent.Builder(TYPE_SMART_ACTION)
704    *         .setEventContext(classificationContext)
705    *         .setResultId(textClassification.getId())
706    *         .setEntityTypes(language)
707    *         .setScore(score)
708    *         .setActionIndices(textClassification.getActions().indexOf(translateAction))
709    *         .setEventIndex(1)
710    *         .build();
711    */
712   public static final class LanguageDetectionEvent extends TextClassifierEvent {
713 
LanguageDetectionEvent(LanguageDetectionEvent.Builder builder)714     private LanguageDetectionEvent(LanguageDetectionEvent.Builder builder) {
715       super(builder);
716     }
717 
718     /** Builder class for {@link LanguageDetectionEvent}. */
719     public static final class Builder
720         extends TextClassifierEvent.Builder<LanguageDetectionEvent.Builder> {
721 
722       /**
723        * Creates a builder for building {@link TextSelectionEvent}s.
724        *
725        * @param eventType The event type. e.g. {@link #TYPE_SMART_ACTION}
726        */
Builder(@ype int eventType)727       public Builder(@Type int eventType) {
728         super(TextClassifierEvent.CATEGORY_LANGUAGE_DETECTION, eventType);
729       }
730 
731       @Override
self()732       Builder self() {
733         return this;
734       }
735 
736       /** Builds and returns a {@link LanguageDetectionEvent}. */
737       @Nonnull
build()738       public LanguageDetectionEvent build() {
739         return new LanguageDetectionEvent(this);
740       }
741     }
742   }
743 
744   /**
745    * This class represents events that are related to the conversation actions feature.
746    *
747    * <p>
748    *
749    * <pre>
750    *     // Conversation (contextual) actions/replies generated.
751    *     new ConversationActionsEvent.Builder(TYPE_ACTIONS_GENERATED)
752    *         .setEventContext(classificationContext)
753    *         .setResultId(conversationActions.getId())
754    *         .setEntityTypes(getTypes(conversationActions))
755    *         .setActionIndices(range(conversationActions.getActions().size()))
756    *         .setEventIndex(0)
757    *         .build();
758    *
759    *     // Conversation actions/replies presented to user.
760    *     new ConversationActionsEvent.Builder(TYPE_ACTIONS_SHOWN)
761    *         .setEventContext(classificationContext)
762    *         .setResultId(conversationActions.getId())
763    *         .setEntityTypes(getTypes(conversationActions))
764    *         .setActionIndices(range(conversationActions.getActions().size()))
765    *         .setEventIndex(1)
766    *         .build();
767    *
768    *     // User clicked the "Reply" button to compose their custom reply.
769    *     new ConversationActionsEvent.Builder(TYPE_MANUAL_REPLY)
770    *         .setEventContext(classificationContext)
771    *         .setResultId(conversationActions.getId())
772    *         .setEventIndex(2)
773    *         .build();
774    *
775    *     // User selected a smart (contextual) action/reply.
776    *     new ConversationActionsEvent.Builder(TYPE_SMART_ACTION)
777    *         .setEventContext(classificationContext)
778    *         .setResultId(conversationActions.getId())
779    *         .setEntityTypes(conversationActions.get(1).getType())
780    *         .setScore(conversationAction.get(1).getConfidenceScore())
781    *         .setActionIndices(1)
782    *         .setEventIndex(2)
783    *         .build();
784    * </pre>
785    */
786   public static final class ConversationActionsEvent extends TextClassifierEvent {
787 
ConversationActionsEvent(ConversationActionsEvent.Builder builder)788     private ConversationActionsEvent(ConversationActionsEvent.Builder builder) {
789       super(builder);
790     }
791 
792     /** Builder class for {@link ConversationActionsEvent}. */
793     public static final class Builder
794         extends TextClassifierEvent.Builder<ConversationActionsEvent.Builder> {
795       /**
796        * Creates a builder for building {@link TextSelectionEvent}s.
797        *
798        * @param eventType The event type. e.g. {@link #TYPE_SMART_ACTION}
799        */
Builder(@ype int eventType)800       public Builder(@Type int eventType) {
801         super(TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS, eventType);
802       }
803 
804       @Override
self()805       Builder self() {
806         return this;
807       }
808 
809       /** Builds and returns a {@link ConversationActionsEvent}. */
810       @Nonnull
build()811       public ConversationActionsEvent build() {
812         return new ConversationActionsEvent(this);
813       }
814     }
815   }
816 }
817