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