1 /* 2 * Copyright (C) 2017 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 android.view.textclassifier; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.view.textclassifier.TextClassifier.EntityType; 25 import android.view.textclassifier.TextClassifier.WidgetType; 26 27 import com.android.internal.annotations.VisibleForTesting; 28 import com.android.internal.util.Preconditions; 29 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 import java.util.Locale; 33 import java.util.Objects; 34 35 /** 36 * A selection event. 37 * Specify index parameters as word token indices. 38 */ 39 public final class SelectionEvent implements Parcelable { 40 41 /** @hide */ 42 @Retention(RetentionPolicy.SOURCE) 43 @IntDef({ACTION_OVERTYPE, ACTION_COPY, ACTION_PASTE, ACTION_CUT, 44 ACTION_SHARE, ACTION_SMART_SHARE, ACTION_DRAG, ACTION_ABANDON, 45 ACTION_OTHER, ACTION_SELECT_ALL, ACTION_RESET}) 46 // NOTE: ActionType values should not be lower than 100 to avoid colliding with the other 47 // EventTypes declared below. 48 public @interface ActionType { 49 /* 50 * Terminal event types range: [100,200). 51 * Non-terminal event types range: [200,300). 52 */ 53 } 54 55 /** User typed over the selection. */ 56 public static final int ACTION_OVERTYPE = 100; 57 /** User copied the selection. */ 58 public static final int ACTION_COPY = 101; 59 /** User pasted over the selection. */ 60 public static final int ACTION_PASTE = 102; 61 /** User cut the selection. */ 62 public static final int ACTION_CUT = 103; 63 /** User shared the selection. */ 64 public static final int ACTION_SHARE = 104; 65 /** User clicked the textAssist menu item. */ 66 public static final int ACTION_SMART_SHARE = 105; 67 /** User dragged+dropped the selection. */ 68 public static final int ACTION_DRAG = 106; 69 /** User abandoned the selection. */ 70 public static final int ACTION_ABANDON = 107; 71 /** User performed an action on the selection. */ 72 public static final int ACTION_OTHER = 108; 73 74 // Non-terminal actions. 75 /** User activated Select All */ 76 public static final int ACTION_SELECT_ALL = 200; 77 /** User reset the smart selection. */ 78 public static final int ACTION_RESET = 201; 79 80 /** @hide */ 81 @Retention(RetentionPolicy.SOURCE) 82 @IntDef({ACTION_OVERTYPE, ACTION_COPY, ACTION_PASTE, ACTION_CUT, 83 ACTION_SHARE, ACTION_SMART_SHARE, ACTION_DRAG, ACTION_ABANDON, 84 ACTION_OTHER, ACTION_SELECT_ALL, ACTION_RESET, 85 EVENT_SELECTION_STARTED, EVENT_SELECTION_MODIFIED, 86 EVENT_SMART_SELECTION_SINGLE, EVENT_SMART_SELECTION_MULTI, 87 EVENT_AUTO_SELECTION}) 88 // NOTE: EventTypes declared here must be less than 100 to avoid colliding with the 89 // ActionTypes declared above. 90 public @interface EventType { 91 /* 92 * Range: 1 -> 99. 93 */ 94 } 95 96 /** User started a new selection. */ 97 public static final int EVENT_SELECTION_STARTED = 1; 98 /** User modified an existing selection. */ 99 public static final int EVENT_SELECTION_MODIFIED = 2; 100 /** Smart selection triggered for a single token (word). */ 101 public static final int EVENT_SMART_SELECTION_SINGLE = 3; 102 /** Smart selection triggered spanning multiple tokens (words). */ 103 public static final int EVENT_SMART_SELECTION_MULTI = 4; 104 /** Something else other than User or the default TextClassifier triggered a selection. */ 105 public static final int EVENT_AUTO_SELECTION = 5; 106 107 /** @hide */ 108 @Retention(RetentionPolicy.SOURCE) 109 @IntDef({INVOCATION_MANUAL, INVOCATION_LINK, INVOCATION_UNKNOWN}) 110 public @interface InvocationMethod {} 111 112 /** Selection was invoked by the user long pressing, double tapping, or dragging to select. */ 113 public static final int INVOCATION_MANUAL = 1; 114 /** Selection was invoked by the user tapping on a link. */ 115 public static final int INVOCATION_LINK = 2; 116 /** Unknown invocation method */ 117 public static final int INVOCATION_UNKNOWN = 0; 118 119 static final String NO_SIGNATURE = ""; 120 121 private final int mAbsoluteStart; 122 private final int mAbsoluteEnd; 123 124 private @EntityType String mEntityType; 125 private @EventType int mEventType; 126 private String mPackageName = ""; 127 private String mWidgetType = TextClassifier.WIDGET_TYPE_UNKNOWN; 128 private @InvocationMethod int mInvocationMethod; 129 @Nullable private String mWidgetVersion; 130 @Nullable private String mResultId; 131 private long mEventTime; 132 private long mDurationSinceSessionStart; 133 private long mDurationSincePreviousEvent; 134 private int mEventIndex; 135 @Nullable private TextClassificationSessionId mSessionId; 136 private int mStart; 137 private int mEnd; 138 private int mSmartStart; 139 private int mSmartEnd; 140 @Nullable private SystemTextClassifierMetadata mSystemTcMetadata; 141 SelectionEvent( int start, int end, @EventType int eventType, @EntityType String entityType, @InvocationMethod int invocationMethod, @Nullable String resultId)142 SelectionEvent( 143 int start, int end, 144 @EventType int eventType, @EntityType String entityType, 145 @InvocationMethod int invocationMethod, @Nullable String resultId) { 146 Preconditions.checkArgument(end >= start, "end cannot be less than start"); 147 mAbsoluteStart = start; 148 mAbsoluteEnd = end; 149 mEventType = eventType; 150 mEntityType = Objects.requireNonNull(entityType); 151 mResultId = resultId; 152 mInvocationMethod = invocationMethod; 153 } 154 SelectionEvent(Parcel in)155 private SelectionEvent(Parcel in) { 156 mAbsoluteStart = in.readInt(); 157 mAbsoluteEnd = in.readInt(); 158 mEventType = in.readInt(); 159 mEntityType = in.readString(); 160 mWidgetVersion = in.readInt() > 0 ? in.readString() : null; 161 mPackageName = in.readString(); 162 mWidgetType = in.readString(); 163 mInvocationMethod = in.readInt(); 164 mResultId = in.readString(); 165 mEventTime = in.readLong(); 166 mDurationSinceSessionStart = in.readLong(); 167 mDurationSincePreviousEvent = in.readLong(); 168 mEventIndex = in.readInt(); 169 mSessionId = in.readInt() > 0 170 ? TextClassificationSessionId.CREATOR.createFromParcel(in) : null; 171 mStart = in.readInt(); 172 mEnd = in.readInt(); 173 mSmartStart = in.readInt(); 174 mSmartEnd = in.readInt(); 175 mSystemTcMetadata = in.readParcelable(null); 176 } 177 178 @Override writeToParcel(Parcel dest, int flags)179 public void writeToParcel(Parcel dest, int flags) { 180 dest.writeInt(mAbsoluteStart); 181 dest.writeInt(mAbsoluteEnd); 182 dest.writeInt(mEventType); 183 dest.writeString(mEntityType); 184 dest.writeInt(mWidgetVersion != null ? 1 : 0); 185 if (mWidgetVersion != null) { 186 dest.writeString(mWidgetVersion); 187 } 188 dest.writeString(mPackageName); 189 dest.writeString(mWidgetType); 190 dest.writeInt(mInvocationMethod); 191 dest.writeString(mResultId); 192 dest.writeLong(mEventTime); 193 dest.writeLong(mDurationSinceSessionStart); 194 dest.writeLong(mDurationSincePreviousEvent); 195 dest.writeInt(mEventIndex); 196 dest.writeInt(mSessionId != null ? 1 : 0); 197 if (mSessionId != null) { 198 mSessionId.writeToParcel(dest, flags); 199 } 200 dest.writeInt(mStart); 201 dest.writeInt(mEnd); 202 dest.writeInt(mSmartStart); 203 dest.writeInt(mSmartEnd); 204 dest.writeParcelable(mSystemTcMetadata, flags); 205 } 206 207 @Override describeContents()208 public int describeContents() { 209 return 0; 210 } 211 212 /** 213 * Creates a "selection started" event. 214 * 215 * @param invocationMethod the way the selection was triggered 216 * @param start the index of the selected text 217 */ 218 @NonNull createSelectionStartedEvent( @electionEvent.InvocationMethod int invocationMethod, int start)219 public static SelectionEvent createSelectionStartedEvent( 220 @SelectionEvent.InvocationMethod int invocationMethod, int start) { 221 return new SelectionEvent( 222 start, start + 1, SelectionEvent.EVENT_SELECTION_STARTED, 223 TextClassifier.TYPE_UNKNOWN, invocationMethod, NO_SIGNATURE); 224 } 225 226 /** 227 * Creates a "selection modified" event. 228 * Use when the user modifies the selection. 229 * 230 * @param start the start (inclusive) index of the selection 231 * @param end the end (exclusive) index of the selection 232 * 233 * @throws IllegalArgumentException if end is less than start 234 */ 235 @NonNull createSelectionModifiedEvent(int start, int end)236 public static SelectionEvent createSelectionModifiedEvent(int start, int end) { 237 Preconditions.checkArgument(end >= start, "end cannot be less than start"); 238 return new SelectionEvent( 239 start, end, SelectionEvent.EVENT_SELECTION_MODIFIED, 240 TextClassifier.TYPE_UNKNOWN, INVOCATION_UNKNOWN, NO_SIGNATURE); 241 } 242 243 /** 244 * Creates a "selection modified" event. 245 * Use when the user modifies the selection and the selection's entity type is known. 246 * 247 * @param start the start (inclusive) index of the selection 248 * @param end the end (exclusive) index of the selection 249 * @param classification the TextClassification object returned by the TextClassifier that 250 * classified the selected text 251 * 252 * @throws IllegalArgumentException if end is less than start 253 */ 254 @NonNull createSelectionModifiedEvent( int start, int end, @NonNull TextClassification classification)255 public static SelectionEvent createSelectionModifiedEvent( 256 int start, int end, @NonNull TextClassification classification) { 257 Preconditions.checkArgument(end >= start, "end cannot be less than start"); 258 Objects.requireNonNull(classification); 259 final String entityType = classification.getEntityCount() > 0 260 ? classification.getEntity(0) 261 : TextClassifier.TYPE_UNKNOWN; 262 return new SelectionEvent( 263 start, end, SelectionEvent.EVENT_SELECTION_MODIFIED, 264 entityType, INVOCATION_UNKNOWN, classification.getId()); 265 } 266 267 /** 268 * Creates a "selection modified" event. 269 * Use when a TextClassifier modifies the selection. 270 * 271 * @param start the start (inclusive) index of the selection 272 * @param end the end (exclusive) index of the selection 273 * @param selection the TextSelection object returned by the TextClassifier for the 274 * specified selection 275 * 276 * @throws IllegalArgumentException if end is less than start 277 */ 278 @NonNull createSelectionModifiedEvent( int start, int end, @NonNull TextSelection selection)279 public static SelectionEvent createSelectionModifiedEvent( 280 int start, int end, @NonNull TextSelection selection) { 281 Preconditions.checkArgument(end >= start, "end cannot be less than start"); 282 Objects.requireNonNull(selection); 283 final String entityType = selection.getEntityCount() > 0 284 ? selection.getEntity(0) 285 : TextClassifier.TYPE_UNKNOWN; 286 return new SelectionEvent( 287 start, end, SelectionEvent.EVENT_AUTO_SELECTION, 288 entityType, INVOCATION_UNKNOWN, selection.getId()); 289 } 290 291 /** 292 * Creates an event specifying an action taken on a selection. 293 * Use when the user clicks on an action to act on the selected text. 294 * 295 * @param start the start (inclusive) index of the selection 296 * @param end the end (exclusive) index of the selection 297 * @param actionType the action that was performed on the selection 298 * 299 * @throws IllegalArgumentException if end is less than start 300 */ 301 @NonNull createSelectionActionEvent( int start, int end, @SelectionEvent.ActionType int actionType)302 public static SelectionEvent createSelectionActionEvent( 303 int start, int end, @SelectionEvent.ActionType int actionType) { 304 Preconditions.checkArgument(end >= start, "end cannot be less than start"); 305 checkActionType(actionType); 306 return new SelectionEvent( 307 start, end, actionType, TextClassifier.TYPE_UNKNOWN, INVOCATION_UNKNOWN, 308 NO_SIGNATURE); 309 } 310 311 /** 312 * Creates an event specifying an action taken on a selection. 313 * Use when the user clicks on an action to act on the selected text and the selection's 314 * entity type is known. 315 * 316 * @param start the start (inclusive) index of the selection 317 * @param end the end (exclusive) index of the selection 318 * @param actionType the action that was performed on the selection 319 * @param classification the TextClassification object returned by the TextClassifier that 320 * classified the selected text 321 * 322 * @throws IllegalArgumentException if end is less than start 323 * @throws IllegalArgumentException If actionType is not a valid SelectionEvent actionType 324 */ 325 @NonNull createSelectionActionEvent( int start, int end, @SelectionEvent.ActionType int actionType, @NonNull TextClassification classification)326 public static SelectionEvent createSelectionActionEvent( 327 int start, int end, @SelectionEvent.ActionType int actionType, 328 @NonNull TextClassification classification) { 329 Preconditions.checkArgument(end >= start, "end cannot be less than start"); 330 Objects.requireNonNull(classification); 331 checkActionType(actionType); 332 final String entityType = classification.getEntityCount() > 0 333 ? classification.getEntity(0) 334 : TextClassifier.TYPE_UNKNOWN; 335 return new SelectionEvent(start, end, actionType, entityType, INVOCATION_UNKNOWN, 336 classification.getId()); 337 } 338 339 /** 340 * @throws IllegalArgumentException If eventType is not an {@link SelectionEvent.ActionType} 341 */ checkActionType(@electionEvent.EventType int eventType)342 private static void checkActionType(@SelectionEvent.EventType int eventType) 343 throws IllegalArgumentException { 344 switch (eventType) { 345 case SelectionEvent.ACTION_OVERTYPE: // fall through 346 case SelectionEvent.ACTION_COPY: // fall through 347 case SelectionEvent.ACTION_PASTE: // fall through 348 case SelectionEvent.ACTION_CUT: // fall through 349 case SelectionEvent.ACTION_SHARE: // fall through 350 case SelectionEvent.ACTION_SMART_SHARE: // fall through 351 case SelectionEvent.ACTION_DRAG: // fall through 352 case SelectionEvent.ACTION_ABANDON: // fall through 353 case SelectionEvent.ACTION_SELECT_ALL: // fall through 354 case SelectionEvent.ACTION_RESET: // fall through 355 case SelectionEvent.ACTION_OTHER: // fall through 356 return; 357 default: 358 throw new IllegalArgumentException( 359 String.format(Locale.US, "%d is not an eventType", eventType)); 360 } 361 } 362 getAbsoluteStart()363 int getAbsoluteStart() { 364 return mAbsoluteStart; 365 } 366 getAbsoluteEnd()367 int getAbsoluteEnd() { 368 return mAbsoluteEnd; 369 } 370 371 /** 372 * Returns the type of event that was triggered. e.g. {@link #ACTION_COPY}. 373 */ 374 @EventType getEventType()375 public int getEventType() { 376 return mEventType; 377 } 378 379 /** 380 * Sets the event type. 381 * @hide 382 */ 383 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setEventType(@ventType int eventType)384 public void setEventType(@EventType int eventType) { 385 mEventType = eventType; 386 } 387 388 /** 389 * Returns the type of entity that is associated with this event. e.g. 390 * {@link android.view.textclassifier.TextClassifier#TYPE_EMAIL}. 391 */ 392 @EntityType 393 @NonNull getEntityType()394 public String getEntityType() { 395 return mEntityType; 396 } 397 setEntityType(@ntityType String entityType)398 void setEntityType(@EntityType String entityType) { 399 mEntityType = Objects.requireNonNull(entityType); 400 } 401 402 /** 403 * Returns the package name of the app that this event originated in. 404 */ 405 @NonNull getPackageName()406 public String getPackageName() { 407 return mPackageName; 408 } 409 410 /** 411 * Sets the information about the {@link SystemTextClassifier} that sent this request. 412 * 413 * @hide 414 */ setSystemTextClassifierMetadata(@ullable SystemTextClassifierMetadata systemTcMetadata)415 void setSystemTextClassifierMetadata(@Nullable SystemTextClassifierMetadata systemTcMetadata) { 416 mSystemTcMetadata = systemTcMetadata; 417 } 418 419 /** 420 * Returns the information about the {@link SystemTextClassifier} that sent this request. 421 * 422 * @hide 423 */ 424 @Nullable getSystemTextClassifierMetadata()425 public SystemTextClassifierMetadata getSystemTextClassifierMetadata() { 426 return mSystemTcMetadata; 427 } 428 429 /** 430 * Returns the type of widget that was involved in triggering this event. 431 */ 432 @WidgetType 433 @NonNull getWidgetType()434 public String getWidgetType() { 435 return mWidgetType; 436 } 437 438 /** 439 * Returns a string version info for the widget this event was triggered in. 440 */ 441 @Nullable getWidgetVersion()442 public String getWidgetVersion() { 443 return mWidgetVersion; 444 } 445 446 /** 447 * Sets the {@link TextClassificationContext} for this event. 448 * @hide 449 */ 450 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setTextClassificationSessionContext(TextClassificationContext context)451 public void setTextClassificationSessionContext(TextClassificationContext context) { 452 mPackageName = context.getPackageName(); 453 mWidgetType = context.getWidgetType(); 454 mWidgetVersion = context.getWidgetVersion(); 455 mSystemTcMetadata = context.getSystemTextClassifierMetadata(); 456 } 457 458 /** 459 * Returns the way the selection mode was invoked. 460 */ getInvocationMethod()461 public @InvocationMethod int getInvocationMethod() { 462 return mInvocationMethod; 463 } 464 465 /** 466 * Sets the invocationMethod for this event. 467 * @hide 468 */ 469 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setInvocationMethod(@nvocationMethod int invocationMethod)470 public void setInvocationMethod(@InvocationMethod int invocationMethod) { 471 mInvocationMethod = invocationMethod; 472 } 473 474 /** 475 * Returns the id of the text classifier result associated with this event. 476 */ 477 @Nullable getResultId()478 public String getResultId() { 479 return mResultId; 480 } 481 setResultId(@ullable String resultId)482 SelectionEvent setResultId(@Nullable String resultId) { 483 mResultId = resultId; 484 return this; 485 } 486 487 /** 488 * Returns the time this event was triggered. 489 */ getEventTime()490 public long getEventTime() { 491 return mEventTime; 492 } 493 setEventTime(long timeMs)494 SelectionEvent setEventTime(long timeMs) { 495 mEventTime = timeMs; 496 return this; 497 } 498 499 /** 500 * Returns the duration in ms between when this event was triggered and when the first event in 501 * the selection session was triggered. 502 */ getDurationSinceSessionStart()503 public long getDurationSinceSessionStart() { 504 return mDurationSinceSessionStart; 505 } 506 setDurationSinceSessionStart(long durationMs)507 SelectionEvent setDurationSinceSessionStart(long durationMs) { 508 mDurationSinceSessionStart = durationMs; 509 return this; 510 } 511 512 /** 513 * Returns the duration in ms between when this event was triggered and when the previous event 514 * in the selection session was triggered. 515 */ getDurationSincePreviousEvent()516 public long getDurationSincePreviousEvent() { 517 return mDurationSincePreviousEvent; 518 } 519 setDurationSincePreviousEvent(long durationMs)520 SelectionEvent setDurationSincePreviousEvent(long durationMs) { 521 this.mDurationSincePreviousEvent = durationMs; 522 return this; 523 } 524 525 /** 526 * Returns the index (e.g. 1st event, 2nd event, etc.) of this event in the selection session. 527 */ getEventIndex()528 public int getEventIndex() { 529 return mEventIndex; 530 } 531 532 /** @hide */ 533 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setEventIndex(int index)534 public SelectionEvent setEventIndex(int index) { 535 mEventIndex = index; 536 return this; 537 } 538 539 /** 540 * Returns the selection session id. 541 */ 542 @Nullable getSessionId()543 public TextClassificationSessionId getSessionId() { 544 return mSessionId; 545 } 546 547 /** @hide */ 548 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setSessionId(@ullable TextClassificationSessionId id)549 public SelectionEvent setSessionId(@Nullable TextClassificationSessionId id) { 550 mSessionId = id; 551 return this; 552 } 553 554 /** 555 * Returns the start index of this events relative to the index of the start selection 556 * event in the selection session. 557 */ getStart()558 public int getStart() { 559 return mStart; 560 } 561 562 /** @hide */ 563 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setStart(int start)564 public SelectionEvent setStart(int start) { 565 mStart = start; 566 return this; 567 } 568 569 /** 570 * Returns the end index of this events relative to the index of the start selection 571 * event in the selection session. 572 */ getEnd()573 public int getEnd() { 574 return mEnd; 575 } 576 577 /** @hide */ 578 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setEnd(int end)579 public SelectionEvent setEnd(int end) { 580 mEnd = end; 581 return this; 582 } 583 584 /** 585 * Returns the start index of this events relative to the index of the smart selection 586 * event in the selection session. 587 */ getSmartStart()588 public int getSmartStart() { 589 return mSmartStart; 590 } 591 592 /** @hide */ 593 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setSmartStart(int start)594 public SelectionEvent setSmartStart(int start) { 595 this.mSmartStart = start; 596 return this; 597 } 598 599 /** 600 * Returns the end index of this events relative to the index of the smart selection 601 * event in the selection session. 602 */ getSmartEnd()603 public int getSmartEnd() { 604 return mSmartEnd; 605 } 606 607 /** @hide */ 608 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setSmartEnd(int end)609 public SelectionEvent setSmartEnd(int end) { 610 mSmartEnd = end; 611 return this; 612 } 613 isTerminal()614 boolean isTerminal() { 615 return isTerminal(mEventType); 616 } 617 618 /** 619 * Returns true if the eventType is a terminal event type. Otherwise returns false. 620 * A terminal event is an event that ends a selection interaction. 621 */ isTerminal(@ventType int eventType)622 public static boolean isTerminal(@EventType int eventType) { 623 switch (eventType) { 624 case ACTION_OVERTYPE: // fall through 625 case ACTION_COPY: // fall through 626 case ACTION_PASTE: // fall through 627 case ACTION_CUT: // fall through 628 case ACTION_SHARE: // fall through 629 case ACTION_SMART_SHARE: // fall through 630 case ACTION_DRAG: // fall through 631 case ACTION_ABANDON: // fall through 632 case ACTION_OTHER: // fall through 633 return true; 634 default: 635 return false; 636 } 637 } 638 639 @Override hashCode()640 public int hashCode() { 641 return Objects.hash(mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType, 642 mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod, mResultId, 643 mEventTime, mDurationSinceSessionStart, mDurationSincePreviousEvent, 644 mEventIndex, mSessionId, mStart, mEnd, mSmartStart, mSmartEnd, mSystemTcMetadata); 645 } 646 647 @Override equals(Object obj)648 public boolean equals(Object obj) { 649 if (this == obj) { 650 return true; 651 } 652 if (!(obj instanceof SelectionEvent)) { 653 return false; 654 } 655 656 final SelectionEvent other = (SelectionEvent) obj; 657 return mAbsoluteStart == other.mAbsoluteStart 658 && mAbsoluteEnd == other.mAbsoluteEnd 659 && mEventType == other.mEventType 660 && Objects.equals(mEntityType, other.mEntityType) 661 && Objects.equals(mWidgetVersion, other.mWidgetVersion) 662 && Objects.equals(mPackageName, other.mPackageName) 663 && Objects.equals(mWidgetType, other.mWidgetType) 664 && mInvocationMethod == other.mInvocationMethod 665 && Objects.equals(mResultId, other.mResultId) 666 && mEventTime == other.mEventTime 667 && mDurationSinceSessionStart == other.mDurationSinceSessionStart 668 && mDurationSincePreviousEvent == other.mDurationSincePreviousEvent 669 && mEventIndex == other.mEventIndex 670 && Objects.equals(mSessionId, other.mSessionId) 671 && mStart == other.mStart 672 && mEnd == other.mEnd 673 && mSmartStart == other.mSmartStart 674 && mSmartEnd == other.mSmartEnd 675 && mSystemTcMetadata == other.mSystemTcMetadata; 676 } 677 678 @Override toString()679 public String toString() { 680 return String.format(Locale.US, 681 "SelectionEvent {absoluteStart=%d, absoluteEnd=%d, eventType=%d, entityType=%s, " 682 + "widgetVersion=%s, packageName=%s, widgetType=%s, invocationMethod=%s, " 683 + "resultId=%s, eventTime=%d, durationSinceSessionStart=%d, " 684 + "durationSincePreviousEvent=%d, eventIndex=%d," 685 + "sessionId=%s, start=%d, end=%d, smartStart=%d, smartEnd=%d, " 686 + "systemTcMetadata=%s}", 687 mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType, 688 mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod, 689 mResultId, mEventTime, mDurationSinceSessionStart, mDurationSincePreviousEvent, 690 mEventIndex, mSessionId, mStart, mEnd, mSmartStart, mSmartEnd, mSystemTcMetadata); 691 } 692 693 public static final @android.annotation.NonNull Creator<SelectionEvent> CREATOR = new Creator<SelectionEvent>() { 694 @Override 695 public SelectionEvent createFromParcel(Parcel in) { 696 return new SelectionEvent(in); 697 } 698 699 @Override 700 public SelectionEvent[] newArray(int size) { 701 return new SelectionEvent[size]; 702 } 703 }; 704 } 705