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 private final @EntityType String mEntityType; 124 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 SelectionEvent( int start, int end, @EventType int eventType, @EntityType String entityType, @InvocationMethod int invocationMethod, @Nullable String resultId)141 SelectionEvent( 142 int start, int end, 143 @EventType int eventType, @EntityType String entityType, 144 @InvocationMethod int invocationMethod, @Nullable String resultId) { 145 Preconditions.checkArgument(end >= start, "end cannot be less than start"); 146 mAbsoluteStart = start; 147 mAbsoluteEnd = end; 148 mEventType = eventType; 149 mEntityType = Preconditions.checkNotNull(entityType); 150 mResultId = resultId; 151 mInvocationMethod = invocationMethod; 152 } 153 SelectionEvent(Parcel in)154 private SelectionEvent(Parcel in) { 155 mAbsoluteStart = in.readInt(); 156 mAbsoluteEnd = in.readInt(); 157 mEventType = in.readInt(); 158 mEntityType = in.readString(); 159 mWidgetVersion = in.readInt() > 0 ? in.readString() : null; 160 mPackageName = in.readString(); 161 mWidgetType = in.readString(); 162 mInvocationMethod = in.readInt(); 163 mResultId = in.readString(); 164 mEventTime = in.readLong(); 165 mDurationSinceSessionStart = in.readLong(); 166 mDurationSincePreviousEvent = in.readLong(); 167 mEventIndex = in.readInt(); 168 mSessionId = in.readInt() > 0 169 ? TextClassificationSessionId.CREATOR.createFromParcel(in) : null; 170 mStart = in.readInt(); 171 mEnd = in.readInt(); 172 mSmartStart = in.readInt(); 173 mSmartEnd = in.readInt(); 174 } 175 176 @Override writeToParcel(Parcel dest, int flags)177 public void writeToParcel(Parcel dest, int flags) { 178 dest.writeInt(mAbsoluteStart); 179 dest.writeInt(mAbsoluteEnd); 180 dest.writeInt(mEventType); 181 dest.writeString(mEntityType); 182 dest.writeInt(mWidgetVersion != null ? 1 : 0); 183 if (mWidgetVersion != null) { 184 dest.writeString(mWidgetVersion); 185 } 186 dest.writeString(mPackageName); 187 dest.writeString(mWidgetType); 188 dest.writeInt(mInvocationMethod); 189 dest.writeString(mResultId); 190 dest.writeLong(mEventTime); 191 dest.writeLong(mDurationSinceSessionStart); 192 dest.writeLong(mDurationSincePreviousEvent); 193 dest.writeInt(mEventIndex); 194 dest.writeInt(mSessionId != null ? 1 : 0); 195 if (mSessionId != null) { 196 mSessionId.writeToParcel(dest, flags); 197 } 198 dest.writeInt(mStart); 199 dest.writeInt(mEnd); 200 dest.writeInt(mSmartStart); 201 dest.writeInt(mSmartEnd); 202 } 203 204 @Override describeContents()205 public int describeContents() { 206 return 0; 207 } 208 209 /** 210 * Creates a "selection started" event. 211 * 212 * @param invocationMethod the way the selection was triggered 213 * @param start the index of the selected text 214 */ 215 @NonNull createSelectionStartedEvent( @electionEvent.InvocationMethod int invocationMethod, int start)216 public static SelectionEvent createSelectionStartedEvent( 217 @SelectionEvent.InvocationMethod int invocationMethod, int start) { 218 return new SelectionEvent( 219 start, start + 1, SelectionEvent.EVENT_SELECTION_STARTED, 220 TextClassifier.TYPE_UNKNOWN, invocationMethod, NO_SIGNATURE); 221 } 222 223 /** 224 * Creates a "selection modified" event. 225 * Use when the user modifies the selection. 226 * 227 * @param start the start (inclusive) index of the selection 228 * @param end the end (exclusive) index of the selection 229 * 230 * @throws IllegalArgumentException if end is less than start 231 */ 232 @NonNull createSelectionModifiedEvent(int start, int end)233 public static SelectionEvent createSelectionModifiedEvent(int start, int end) { 234 Preconditions.checkArgument(end >= start, "end cannot be less than start"); 235 return new SelectionEvent( 236 start, end, SelectionEvent.EVENT_SELECTION_MODIFIED, 237 TextClassifier.TYPE_UNKNOWN, INVOCATION_UNKNOWN, NO_SIGNATURE); 238 } 239 240 /** 241 * Creates a "selection modified" event. 242 * Use when the user modifies the selection and the selection's entity type is known. 243 * 244 * @param start the start (inclusive) index of the selection 245 * @param end the end (exclusive) index of the selection 246 * @param classification the TextClassification object returned by the TextClassifier that 247 * classified the selected text 248 * 249 * @throws IllegalArgumentException if end is less than start 250 */ 251 @NonNull createSelectionModifiedEvent( int start, int end, @NonNull TextClassification classification)252 public static SelectionEvent createSelectionModifiedEvent( 253 int start, int end, @NonNull TextClassification classification) { 254 Preconditions.checkArgument(end >= start, "end cannot be less than start"); 255 Preconditions.checkNotNull(classification); 256 final String entityType = classification.getEntityCount() > 0 257 ? classification.getEntity(0) 258 : TextClassifier.TYPE_UNKNOWN; 259 return new SelectionEvent( 260 start, end, SelectionEvent.EVENT_SELECTION_MODIFIED, 261 entityType, INVOCATION_UNKNOWN, classification.getId()); 262 } 263 264 /** 265 * Creates a "selection modified" event. 266 * Use when a TextClassifier modifies the selection. 267 * 268 * @param start the start (inclusive) index of the selection 269 * @param end the end (exclusive) index of the selection 270 * @param selection the TextSelection object returned by the TextClassifier for the 271 * specified selection 272 * 273 * @throws IllegalArgumentException if end is less than start 274 */ 275 @NonNull createSelectionModifiedEvent( int start, int end, @NonNull TextSelection selection)276 public static SelectionEvent createSelectionModifiedEvent( 277 int start, int end, @NonNull TextSelection selection) { 278 Preconditions.checkArgument(end >= start, "end cannot be less than start"); 279 Preconditions.checkNotNull(selection); 280 final String entityType = selection.getEntityCount() > 0 281 ? selection.getEntity(0) 282 : TextClassifier.TYPE_UNKNOWN; 283 return new SelectionEvent( 284 start, end, SelectionEvent.EVENT_AUTO_SELECTION, 285 entityType, INVOCATION_UNKNOWN, selection.getId()); 286 } 287 288 /** 289 * Creates an event specifying an action taken on a selection. 290 * Use when the user clicks on an action to act on the selected text. 291 * 292 * @param start the start (inclusive) index of the selection 293 * @param end the end (exclusive) index of the selection 294 * @param actionType the action that was performed on the selection 295 * 296 * @throws IllegalArgumentException if end is less than start 297 */ 298 @NonNull createSelectionActionEvent( int start, int end, @SelectionEvent.ActionType int actionType)299 public static SelectionEvent createSelectionActionEvent( 300 int start, int end, @SelectionEvent.ActionType int actionType) { 301 Preconditions.checkArgument(end >= start, "end cannot be less than start"); 302 checkActionType(actionType); 303 return new SelectionEvent( 304 start, end, actionType, TextClassifier.TYPE_UNKNOWN, INVOCATION_UNKNOWN, 305 NO_SIGNATURE); 306 } 307 308 /** 309 * Creates an event specifying an action taken on a selection. 310 * Use when the user clicks on an action to act on the selected text and the selection's 311 * entity type is known. 312 * 313 * @param start the start (inclusive) index of the selection 314 * @param end the end (exclusive) index of the selection 315 * @param actionType the action that was performed on the selection 316 * @param classification the TextClassification object returned by the TextClassifier that 317 * classified the selected text 318 * 319 * @throws IllegalArgumentException if end is less than start 320 * @throws IllegalArgumentException If actionType is not a valid SelectionEvent actionType 321 */ 322 @NonNull createSelectionActionEvent( int start, int end, @SelectionEvent.ActionType int actionType, @NonNull TextClassification classification)323 public static SelectionEvent createSelectionActionEvent( 324 int start, int end, @SelectionEvent.ActionType int actionType, 325 @NonNull TextClassification classification) { 326 Preconditions.checkArgument(end >= start, "end cannot be less than start"); 327 Preconditions.checkNotNull(classification); 328 checkActionType(actionType); 329 final String entityType = classification.getEntityCount() > 0 330 ? classification.getEntity(0) 331 : TextClassifier.TYPE_UNKNOWN; 332 return new SelectionEvent(start, end, actionType, entityType, INVOCATION_UNKNOWN, 333 classification.getId()); 334 } 335 336 /** 337 * @throws IllegalArgumentException If eventType is not an {@link SelectionEvent.ActionType} 338 */ checkActionType(@electionEvent.EventType int eventType)339 private static void checkActionType(@SelectionEvent.EventType int eventType) 340 throws IllegalArgumentException { 341 switch (eventType) { 342 case SelectionEvent.ACTION_OVERTYPE: // fall through 343 case SelectionEvent.ACTION_COPY: // fall through 344 case SelectionEvent.ACTION_PASTE: // fall through 345 case SelectionEvent.ACTION_CUT: // fall through 346 case SelectionEvent.ACTION_SHARE: // fall through 347 case SelectionEvent.ACTION_SMART_SHARE: // fall through 348 case SelectionEvent.ACTION_DRAG: // fall through 349 case SelectionEvent.ACTION_ABANDON: // fall through 350 case SelectionEvent.ACTION_SELECT_ALL: // fall through 351 case SelectionEvent.ACTION_RESET: // fall through 352 case SelectionEvent.ACTION_OTHER: // fall through 353 return; 354 default: 355 throw new IllegalArgumentException( 356 String.format(Locale.US, "%d is not an eventType", eventType)); 357 } 358 } 359 getAbsoluteStart()360 int getAbsoluteStart() { 361 return mAbsoluteStart; 362 } 363 getAbsoluteEnd()364 int getAbsoluteEnd() { 365 return mAbsoluteEnd; 366 } 367 368 /** 369 * Returns the type of event that was triggered. e.g. {@link #ACTION_COPY}. 370 */ 371 @EventType getEventType()372 public int getEventType() { 373 return mEventType; 374 } 375 376 /** 377 * Sets the event type. 378 * @hide 379 */ 380 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setEventType(@ventType int eventType)381 public void setEventType(@EventType int eventType) { 382 mEventType = eventType; 383 } 384 385 /** 386 * Returns the type of entity that is associated with this event. e.g. 387 * {@link android.view.textclassifier.TextClassifier#TYPE_EMAIL}. 388 */ 389 @EntityType 390 @NonNull getEntityType()391 public String getEntityType() { 392 return mEntityType; 393 } 394 395 /** 396 * Returns the package name of the app that this event originated in. 397 */ 398 @NonNull getPackageName()399 public String getPackageName() { 400 return mPackageName; 401 } 402 403 /** 404 * Returns the type of widget that was involved in triggering this event. 405 */ 406 @WidgetType 407 @NonNull getWidgetType()408 public String getWidgetType() { 409 return mWidgetType; 410 } 411 412 /** 413 * Returns a string version info for the widget this event was triggered in. 414 */ 415 @Nullable getWidgetVersion()416 public String getWidgetVersion() { 417 return mWidgetVersion; 418 } 419 420 /** 421 * Sets the {@link TextClassificationContext} for this event. 422 * @hide 423 */ 424 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setTextClassificationSessionContext(TextClassificationContext context)425 public void setTextClassificationSessionContext(TextClassificationContext context) { 426 mPackageName = context.getPackageName(); 427 mWidgetType = context.getWidgetType(); 428 mWidgetVersion = context.getWidgetVersion(); 429 } 430 431 /** 432 * Returns the way the selection mode was invoked. 433 */ getInvocationMethod()434 public @InvocationMethod int getInvocationMethod() { 435 return mInvocationMethod; 436 } 437 438 /** 439 * Sets the invocationMethod for this event. 440 * @hide 441 */ 442 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setInvocationMethod(@nvocationMethod int invocationMethod)443 public void setInvocationMethod(@InvocationMethod int invocationMethod) { 444 mInvocationMethod = invocationMethod; 445 } 446 447 /** 448 * Returns the id of the text classifier result associated with this event. 449 */ 450 @Nullable getResultId()451 public String getResultId() { 452 return mResultId; 453 } 454 setResultId(@ullable String resultId)455 SelectionEvent setResultId(@Nullable String resultId) { 456 mResultId = resultId; 457 return this; 458 } 459 460 /** 461 * Returns the time this event was triggered. 462 */ getEventTime()463 public long getEventTime() { 464 return mEventTime; 465 } 466 setEventTime(long timeMs)467 SelectionEvent setEventTime(long timeMs) { 468 mEventTime = timeMs; 469 return this; 470 } 471 472 /** 473 * Returns the duration in ms between when this event was triggered and when the first event in 474 * the selection session was triggered. 475 */ getDurationSinceSessionStart()476 public long getDurationSinceSessionStart() { 477 return mDurationSinceSessionStart; 478 } 479 setDurationSinceSessionStart(long durationMs)480 SelectionEvent setDurationSinceSessionStart(long durationMs) { 481 mDurationSinceSessionStart = durationMs; 482 return this; 483 } 484 485 /** 486 * Returns the duration in ms between when this event was triggered and when the previous event 487 * in the selection session was triggered. 488 */ getDurationSincePreviousEvent()489 public long getDurationSincePreviousEvent() { 490 return mDurationSincePreviousEvent; 491 } 492 setDurationSincePreviousEvent(long durationMs)493 SelectionEvent setDurationSincePreviousEvent(long durationMs) { 494 this.mDurationSincePreviousEvent = durationMs; 495 return this; 496 } 497 498 /** 499 * Returns the index (e.g. 1st event, 2nd event, etc.) of this event in the selection session. 500 */ getEventIndex()501 public int getEventIndex() { 502 return mEventIndex; 503 } 504 505 /** @hide */ 506 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setEventIndex(int index)507 public SelectionEvent setEventIndex(int index) { 508 mEventIndex = index; 509 return this; 510 } 511 512 /** 513 * Returns the selection session id. 514 */ 515 @Nullable getSessionId()516 public TextClassificationSessionId getSessionId() { 517 return mSessionId; 518 } 519 520 /** @hide */ 521 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setSessionId(@ullable TextClassificationSessionId id)522 public SelectionEvent setSessionId(@Nullable TextClassificationSessionId id) { 523 mSessionId = id; 524 return this; 525 } 526 527 /** 528 * Returns the start index of this events relative to the index of the start selection 529 * event in the selection session. 530 */ getStart()531 public int getStart() { 532 return mStart; 533 } 534 535 /** @hide */ 536 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setStart(int start)537 public SelectionEvent setStart(int start) { 538 mStart = start; 539 return this; 540 } 541 542 /** 543 * Returns the end index of this events relative to the index of the start selection 544 * event in the selection session. 545 */ getEnd()546 public int getEnd() { 547 return mEnd; 548 } 549 550 /** @hide */ 551 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setEnd(int end)552 public SelectionEvent setEnd(int end) { 553 mEnd = end; 554 return this; 555 } 556 557 /** 558 * Returns the start index of this events relative to the index of the smart selection 559 * event in the selection session. 560 */ getSmartStart()561 public int getSmartStart() { 562 return mSmartStart; 563 } 564 565 /** @hide */ 566 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setSmartStart(int start)567 public SelectionEvent setSmartStart(int start) { 568 this.mSmartStart = start; 569 return this; 570 } 571 572 /** 573 * Returns the end index of this events relative to the index of the smart selection 574 * event in the selection session. 575 */ getSmartEnd()576 public int getSmartEnd() { 577 return mSmartEnd; 578 } 579 580 /** @hide */ 581 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setSmartEnd(int end)582 public SelectionEvent setSmartEnd(int end) { 583 mSmartEnd = end; 584 return this; 585 } 586 isTerminal()587 boolean isTerminal() { 588 return isTerminal(mEventType); 589 } 590 591 /** 592 * Returns true if the eventType is a terminal event type. Otherwise returns false. 593 * A terminal event is an event that ends a selection interaction. 594 */ isTerminal(@ventType int eventType)595 public static boolean isTerminal(@EventType int eventType) { 596 switch (eventType) { 597 case ACTION_OVERTYPE: // fall through 598 case ACTION_COPY: // fall through 599 case ACTION_PASTE: // fall through 600 case ACTION_CUT: // fall through 601 case ACTION_SHARE: // fall through 602 case ACTION_SMART_SHARE: // fall through 603 case ACTION_DRAG: // fall through 604 case ACTION_ABANDON: // fall through 605 case ACTION_OTHER: // fall through 606 return true; 607 default: 608 return false; 609 } 610 } 611 612 @Override hashCode()613 public int hashCode() { 614 return Objects.hash(mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType, 615 mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod, mResultId, 616 mEventTime, mDurationSinceSessionStart, mDurationSincePreviousEvent, 617 mEventIndex, mSessionId, mStart, mEnd, mSmartStart, mSmartEnd); 618 } 619 620 @Override equals(Object obj)621 public boolean equals(Object obj) { 622 if (this == obj) { 623 return true; 624 } 625 if (!(obj instanceof SelectionEvent)) { 626 return false; 627 } 628 629 final SelectionEvent other = (SelectionEvent) obj; 630 return mAbsoluteStart == other.mAbsoluteStart 631 && mAbsoluteEnd == other.mAbsoluteEnd 632 && mEventType == other.mEventType 633 && Objects.equals(mEntityType, other.mEntityType) 634 && Objects.equals(mWidgetVersion, other.mWidgetVersion) 635 && Objects.equals(mPackageName, other.mPackageName) 636 && Objects.equals(mWidgetType, other.mWidgetType) 637 && mInvocationMethod == other.mInvocationMethod 638 && Objects.equals(mResultId, other.mResultId) 639 && mEventTime == other.mEventTime 640 && mDurationSinceSessionStart == other.mDurationSinceSessionStart 641 && mDurationSincePreviousEvent == other.mDurationSincePreviousEvent 642 && mEventIndex == other.mEventIndex 643 && Objects.equals(mSessionId, other.mSessionId) 644 && mStart == other.mStart 645 && mEnd == other.mEnd 646 && mSmartStart == other.mSmartStart 647 && mSmartEnd == other.mSmartEnd; 648 } 649 650 @Override toString()651 public String toString() { 652 return String.format(Locale.US, 653 "SelectionEvent {absoluteStart=%d, absoluteEnd=%d, eventType=%d, entityType=%s, " 654 + "widgetVersion=%s, packageName=%s, widgetType=%s, invocationMethod=%s, " 655 + "resultId=%s, eventTime=%d, durationSinceSessionStart=%d, " 656 + "durationSincePreviousEvent=%d, eventIndex=%d," 657 + "sessionId=%s, start=%d, end=%d, smartStart=%d, smartEnd=%d}", 658 mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType, 659 mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod, 660 mResultId, mEventTime, mDurationSinceSessionStart, 661 mDurationSincePreviousEvent, mEventIndex, 662 mSessionId, mStart, mEnd, mSmartStart, mSmartEnd); 663 } 664 665 public static final @android.annotation.NonNull Creator<SelectionEvent> CREATOR = new Creator<SelectionEvent>() { 666 @Override 667 public SelectionEvent createFromParcel(Parcel in) { 668 return new SelectionEvent(in); 669 } 670 671 @Override 672 public SelectionEvent[] newArray(int size) { 673 return new SelectionEvent[size]; 674 } 675 }; 676 } 677