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 package android.view.contentcapture; 17 18 import static android.view.contentcapture.ContentCaptureHelper.getSanitizedString; 19 import static android.view.contentcapture.ContentCaptureManager.DEBUG; 20 import static android.view.contentcapture.ContentCaptureManager.NO_SESSION_ID; 21 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.SystemApi; 26 import android.graphics.Insets; 27 import android.graphics.Rect; 28 import android.os.Parcel; 29 import android.os.Parcelable; 30 import android.text.Selection; 31 import android.text.Spannable; 32 import android.text.SpannableString; 33 import android.util.Log; 34 import android.view.autofill.AutofillId; 35 import android.view.inputmethod.BaseInputConnection; 36 37 import com.android.internal.util.Preconditions; 38 39 import java.io.PrintWriter; 40 import java.lang.annotation.Retention; 41 import java.lang.annotation.RetentionPolicy; 42 import java.util.ArrayList; 43 import java.util.List; 44 45 /** @hide */ 46 @SystemApi 47 public final class ContentCaptureEvent implements Parcelable { 48 49 private static final String TAG = ContentCaptureEvent.class.getSimpleName(); 50 51 /** @hide */ 52 public static final int TYPE_SESSION_FINISHED = -2; 53 /** @hide */ 54 public static final int TYPE_SESSION_STARTED = -1; 55 56 /** 57 * Called when a node has been added to the screen and is visible to the user. 58 * 59 * <p>The metadata of the node is available through {@link #getViewNode()}. 60 */ 61 public static final int TYPE_VIEW_APPEARED = 1; 62 63 /** 64 * Called when one or more nodes have been removed from the screen and is not visible to the 65 * user anymore. 66 * 67 * <p>To get the id(s), first call {@link #getIds()} - if it returns {@code null}, then call 68 * {@link #getId()}. 69 */ 70 public static final int TYPE_VIEW_DISAPPEARED = 2; 71 72 /** 73 * Called when the text of a node has been changed. 74 * 75 * <p>The id of the node is available through {@link #getId()}, and the new text is 76 * available through {@link #getText()}. 77 */ 78 public static final int TYPE_VIEW_TEXT_CHANGED = 3; 79 80 /** 81 * Called before events (such as {@link #TYPE_VIEW_APPEARED} and/or 82 * {@link #TYPE_VIEW_DISAPPEARED}) representing a view hierarchy are sent. 83 * 84 * <p><b>NOTE</b>: there is no guarantee this event will be sent. For example, it's not sent 85 * if the initial view hierarchy doesn't initially have any view that's important for content 86 * capture. 87 */ 88 public static final int TYPE_VIEW_TREE_APPEARING = 4; 89 90 /** 91 * Called after events (such as {@link #TYPE_VIEW_APPEARED} and/or 92 * {@link #TYPE_VIEW_DISAPPEARED}) representing a view hierarchy were sent. 93 * 94 * <p><b>NOTE</b>: there is no guarantee this event will be sent. For example, it's not sent 95 * if the initial view hierarchy doesn't initially have any view that's important for content 96 * capture. 97 */ 98 public static final int TYPE_VIEW_TREE_APPEARED = 5; 99 100 /** 101 * Called after a call to 102 * {@link ContentCaptureSession#setContentCaptureContext(ContentCaptureContext)}. 103 * 104 * <p>The passed context is available through {@link #getContentCaptureContext()}. 105 */ 106 public static final int TYPE_CONTEXT_UPDATED = 6; 107 108 /** 109 * Called after the session is ready, typically after the activity resumed and the 110 * initial views appeared 111 */ 112 public static final int TYPE_SESSION_RESUMED = 7; 113 114 /** 115 * Called after the session is paused, typically after the activity paused and the 116 * views disappeared. 117 */ 118 public static final int TYPE_SESSION_PAUSED = 8; 119 120 /** 121 * Called when the view's insets are changed. The new insets associated with the 122 * event may then be retrieved by calling {@link #getInsets()} 123 */ 124 public static final int TYPE_VIEW_INSETS_CHANGED = 9; 125 126 /** 127 * Called before {@link #TYPE_VIEW_TREE_APPEARING}, or after the size of the window containing 128 * the views changed. 129 */ 130 public static final int TYPE_WINDOW_BOUNDS_CHANGED = 10; 131 132 /** @hide */ 133 @IntDef(prefix = { "TYPE_" }, value = { 134 TYPE_VIEW_APPEARED, 135 TYPE_VIEW_DISAPPEARED, 136 TYPE_VIEW_TEXT_CHANGED, 137 TYPE_VIEW_TREE_APPEARING, 138 TYPE_VIEW_TREE_APPEARED, 139 TYPE_CONTEXT_UPDATED, 140 TYPE_SESSION_PAUSED, 141 TYPE_SESSION_RESUMED, 142 TYPE_VIEW_INSETS_CHANGED, 143 TYPE_WINDOW_BOUNDS_CHANGED, 144 }) 145 @Retention(RetentionPolicy.SOURCE) 146 public @interface EventType{} 147 148 /** @hide */ 149 public static final int MAX_INVALID_VALUE = -1; 150 151 private final int mSessionId; 152 private final int mType; 153 private final long mEventTime; 154 private @Nullable AutofillId mId; 155 private @Nullable ArrayList<AutofillId> mIds; 156 private @Nullable ViewNode mNode; 157 private @Nullable CharSequence mText; 158 private int mParentSessionId = NO_SESSION_ID; 159 private @Nullable ContentCaptureContext mClientContext; 160 private @Nullable Insets mInsets; 161 private @Nullable Rect mBounds; 162 163 private int mComposingStart = MAX_INVALID_VALUE; 164 private int mComposingEnd = MAX_INVALID_VALUE; 165 private int mSelectionStartIndex = MAX_INVALID_VALUE; 166 private int mSelectionEndIndex = MAX_INVALID_VALUE; 167 168 /** Only used in the main Content Capture session, no need to parcel */ 169 private boolean mTextHasComposingSpan; 170 171 /** @hide */ ContentCaptureEvent(int sessionId, int type, long eventTime)172 public ContentCaptureEvent(int sessionId, int type, long eventTime) { 173 mSessionId = sessionId; 174 mType = type; 175 mEventTime = eventTime; 176 } 177 178 /** @hide */ ContentCaptureEvent(int sessionId, int type)179 public ContentCaptureEvent(int sessionId, int type) { 180 this(sessionId, type, System.currentTimeMillis()); 181 } 182 183 /** @hide */ setAutofillId(@onNull AutofillId id)184 public ContentCaptureEvent setAutofillId(@NonNull AutofillId id) { 185 mId = Preconditions.checkNotNull(id); 186 return this; 187 } 188 189 /** @hide */ setAutofillIds(@onNull ArrayList<AutofillId> ids)190 public ContentCaptureEvent setAutofillIds(@NonNull ArrayList<AutofillId> ids) { 191 mIds = Preconditions.checkNotNull(ids); 192 return this; 193 } 194 195 /** 196 * Adds an autofill id to the this event, merging the single id into a list if necessary. 197 * 198 * @hide 199 */ addAutofillId(@onNull AutofillId id)200 public ContentCaptureEvent addAutofillId(@NonNull AutofillId id) { 201 Preconditions.checkNotNull(id); 202 if (mIds == null) { 203 mIds = new ArrayList<>(); 204 if (mId == null) { 205 Log.w(TAG, "addAutofillId(" + id + ") called without an initial id"); 206 } else { 207 mIds.add(mId); 208 mId = null; 209 } 210 } 211 mIds.add(id); 212 return this; 213 } 214 215 /** 216 * Used by {@link #TYPE_SESSION_STARTED} and {@link #TYPE_SESSION_FINISHED}. 217 * 218 * @hide 219 */ setParentSessionId(int parentSessionId)220 public ContentCaptureEvent setParentSessionId(int parentSessionId) { 221 mParentSessionId = parentSessionId; 222 return this; 223 } 224 225 /** 226 * Used by {@link #TYPE_SESSION_STARTED} and {@link #TYPE_SESSION_FINISHED}. 227 * 228 * @hide 229 */ setClientContext(@onNull ContentCaptureContext clientContext)230 public ContentCaptureEvent setClientContext(@NonNull ContentCaptureContext clientContext) { 231 mClientContext = clientContext; 232 return this; 233 } 234 235 /** @hide */ 236 @NonNull getSessionId()237 public int getSessionId() { 238 return mSessionId; 239 } 240 241 /** 242 * Used by {@link #TYPE_SESSION_STARTED} and {@link #TYPE_SESSION_FINISHED}. 243 * 244 * @hide 245 */ 246 @Nullable getParentSessionId()247 public int getParentSessionId() { 248 return mParentSessionId; 249 } 250 251 /** 252 * Gets the {@link ContentCaptureContext} set calls to 253 * {@link ContentCaptureSession#setContentCaptureContext(ContentCaptureContext)}. 254 * 255 * <p>Only set on {@link #TYPE_CONTEXT_UPDATED} events. 256 */ 257 @Nullable getContentCaptureContext()258 public ContentCaptureContext getContentCaptureContext() { 259 return mClientContext; 260 } 261 262 /** @hide */ 263 @NonNull setViewNode(@onNull ViewNode node)264 public ContentCaptureEvent setViewNode(@NonNull ViewNode node) { 265 mNode = Preconditions.checkNotNull(node); 266 return this; 267 } 268 269 /** @hide */ 270 @NonNull setText(@ullable CharSequence text)271 public ContentCaptureEvent setText(@Nullable CharSequence text) { 272 mText = text; 273 return this; 274 } 275 276 /** @hide */ 277 @NonNull setComposingIndex(int start, int end)278 public ContentCaptureEvent setComposingIndex(int start, int end) { 279 mComposingStart = start; 280 mComposingEnd = end; 281 return this; 282 } 283 284 /** @hide */ 285 @NonNull hasComposingSpan()286 public boolean hasComposingSpan() { 287 return mComposingStart > MAX_INVALID_VALUE; 288 } 289 290 /** @hide */ 291 @NonNull setSelectionIndex(int start, int end)292 public ContentCaptureEvent setSelectionIndex(int start, int end) { 293 mSelectionStartIndex = start; 294 mSelectionEndIndex = end; 295 return this; 296 } 297 hasSameComposingSpan(@onNull ContentCaptureEvent other)298 boolean hasSameComposingSpan(@NonNull ContentCaptureEvent other) { 299 return mComposingStart == other.mComposingStart && mComposingEnd == other.mComposingEnd; 300 } 301 hasSameSelectionSpan(@onNull ContentCaptureEvent other)302 boolean hasSameSelectionSpan(@NonNull ContentCaptureEvent other) { 303 return mSelectionStartIndex == other.mSelectionStartIndex 304 && mSelectionEndIndex == other.mSelectionEndIndex; 305 } 306 getComposingStart()307 private int getComposingStart() { 308 return mComposingStart; 309 } 310 getComposingEnd()311 private int getComposingEnd() { 312 return mComposingEnd; 313 } 314 getSelectionStart()315 private int getSelectionStart() { 316 return mSelectionStartIndex; 317 } 318 getSelectionEnd()319 private int getSelectionEnd() { 320 return mSelectionEndIndex; 321 } 322 restoreComposingSpan()323 private void restoreComposingSpan() { 324 if (mComposingStart <= MAX_INVALID_VALUE 325 || mComposingEnd <= MAX_INVALID_VALUE) { 326 return; 327 } 328 if (mText instanceof Spannable) { 329 BaseInputConnection.setComposingSpans((Spannable) mText, mComposingStart, 330 mComposingEnd); 331 } else { 332 Log.w(TAG, "Text is not a Spannable."); 333 } 334 } 335 restoreSelectionSpans()336 private void restoreSelectionSpans() { 337 if (mSelectionStartIndex <= MAX_INVALID_VALUE 338 || mSelectionEndIndex <= MAX_INVALID_VALUE) { 339 return; 340 } 341 342 if (mText instanceof SpannableString) { 343 SpannableString ss = (SpannableString) mText; 344 ss.setSpan(Selection.SELECTION_START, mSelectionStartIndex, mSelectionStartIndex, 0); 345 ss.setSpan(Selection.SELECTION_END, mSelectionEndIndex, mSelectionEndIndex, 0); 346 } else { 347 Log.w(TAG, "Text is not a SpannableString."); 348 } 349 } 350 351 /** @hide */ 352 @NonNull setInsets(@onNull Insets insets)353 public ContentCaptureEvent setInsets(@NonNull Insets insets) { 354 mInsets = insets; 355 return this; 356 } 357 358 /** @hide */ 359 @NonNull setBounds(@onNull Rect bounds)360 public ContentCaptureEvent setBounds(@NonNull Rect bounds) { 361 mBounds = bounds; 362 return this; 363 } 364 365 /** 366 * Gets the type of the event. 367 * 368 * @return one of {@link #TYPE_VIEW_APPEARED}, {@link #TYPE_VIEW_DISAPPEARED}, 369 * {@link #TYPE_VIEW_TEXT_CHANGED}, {@link #TYPE_VIEW_TREE_APPEARING}, 370 * {@link #TYPE_VIEW_TREE_APPEARED}, {@link #TYPE_CONTEXT_UPDATED}, 371 * {@link #TYPE_SESSION_RESUMED}, or {@link #TYPE_SESSION_PAUSED}. 372 */ getType()373 public @EventType int getType() { 374 return mType; 375 } 376 377 /** 378 * Gets when the event was generated, in millis since epoch. 379 */ getEventTime()380 public long getEventTime() { 381 return mEventTime; 382 } 383 384 /** 385 * Gets the whole metadata of the node associated with the event. 386 * 387 * <p>Only set on {@link #TYPE_VIEW_APPEARED} events. 388 */ 389 @Nullable getViewNode()390 public ViewNode getViewNode() { 391 return mNode; 392 } 393 394 /** 395 * Gets the {@link AutofillId} of the node associated with the event. 396 * 397 * <p>Only set on {@link #TYPE_VIEW_DISAPPEARED} (when the event contains just one node - if 398 * it contains more than one, this method returns {@code null} and the actual ids should be 399 * retrived by {@link #getIds()}) and {@link #TYPE_VIEW_TEXT_CHANGED} events. 400 */ 401 @Nullable getId()402 public AutofillId getId() { 403 return mId; 404 } 405 406 /** 407 * Gets the {@link AutofillId AutofillIds} of the nodes associated with the event. 408 * 409 * <p>Only set on {@link #TYPE_VIEW_DISAPPEARED}, when the event contains more than one node 410 * (if it contains just one node, it's returned by {@link #getId()} instead. 411 */ 412 @Nullable getIds()413 public List<AutofillId> getIds() { 414 return mIds; 415 } 416 417 /** 418 * Gets the current text of the node associated with the event. 419 * 420 * <p>Only set on {@link #TYPE_VIEW_TEXT_CHANGED} events. 421 */ 422 @Nullable getText()423 public CharSequence getText() { 424 return mText; 425 } 426 427 /** 428 * Gets the rectangle of the insets associated with the event. Valid insets will only be 429 * returned if the type of the event is {@link #TYPE_VIEW_INSETS_CHANGED}, otherwise they 430 * will be null. 431 */ 432 @Nullable getInsets()433 public Insets getInsets() { 434 return mInsets; 435 } 436 437 /** 438 * Gets the {@link Rect} bounds of the window associated with the event. Valid bounds will only 439 * be returned if the type of the event is {@link #TYPE_WINDOW_BOUNDS_CHANGED}, otherwise they 440 * will be null. 441 */ 442 @Nullable getBounds()443 public Rect getBounds() { 444 return mBounds; 445 } 446 447 /** 448 * Merges event of the same type, either {@link #TYPE_VIEW_TEXT_CHANGED} 449 * or {@link #TYPE_VIEW_DISAPPEARED}. 450 * 451 * @hide 452 */ mergeEvent(@onNull ContentCaptureEvent event)453 public void mergeEvent(@NonNull ContentCaptureEvent event) { 454 Preconditions.checkNotNull(event); 455 final int eventType = event.getType(); 456 if (mType != eventType) { 457 Log.e(TAG, "mergeEvent(" + getTypeAsString(eventType) + ") cannot be merged " 458 + "with different eventType=" + getTypeAsString(mType)); 459 return; 460 } 461 462 if (eventType == TYPE_VIEW_DISAPPEARED) { 463 final List<AutofillId> ids = event.getIds(); 464 final AutofillId id = event.getId(); 465 if (ids != null) { 466 if (id != null) { 467 Log.w(TAG, "got TYPE_VIEW_DISAPPEARED event with both id and ids: " + event); 468 } 469 for (int i = 0; i < ids.size(); i++) { 470 addAutofillId(ids.get(i)); 471 } 472 return; 473 } 474 if (id != null) { 475 addAutofillId(id); 476 return; 477 } 478 throw new IllegalArgumentException("mergeEvent(): got " 479 + "TYPE_VIEW_DISAPPEARED event with neither id or ids: " + event); 480 } else if (eventType == TYPE_VIEW_TEXT_CHANGED) { 481 setText(event.getText()); 482 setComposingIndex(event.getComposingStart(), event.getComposingEnd()); 483 setSelectionIndex(event.getSelectionStart(), event.getSelectionEnd()); 484 } else { 485 Log.e(TAG, "mergeEvent(" + getTypeAsString(eventType) 486 + ") does not support this event type."); 487 } 488 } 489 490 /** @hide */ dump(@onNull PrintWriter pw)491 public void dump(@NonNull PrintWriter pw) { 492 pw.print("type="); pw.print(getTypeAsString(mType)); 493 pw.print(", time="); pw.print(mEventTime); 494 if (mId != null) { 495 pw.print(", id="); pw.print(mId); 496 } 497 if (mIds != null) { 498 pw.print(", ids="); pw.print(mIds); 499 } 500 if (mNode != null) { 501 pw.print(", mNode.id="); pw.print(mNode.getAutofillId()); 502 } 503 if (mSessionId != NO_SESSION_ID) { 504 pw.print(", sessionId="); pw.print(mSessionId); 505 } 506 if (mParentSessionId != NO_SESSION_ID) { 507 pw.print(", parentSessionId="); pw.print(mParentSessionId); 508 } 509 if (mText != null) { 510 pw.print(", text="); pw.println(getSanitizedString(mText)); 511 } 512 if (mClientContext != null) { 513 pw.print(", context="); mClientContext.dump(pw); pw.println(); 514 } 515 if (mInsets != null) { 516 pw.print(", insets="); pw.println(mInsets); 517 } 518 if (mBounds != null) { 519 pw.print(", bounds="); pw.println(mBounds); 520 } 521 if (mComposingStart > MAX_INVALID_VALUE) { 522 pw.print(", composing("); pw.print(mComposingStart); 523 pw.print(", "); pw.print(mComposingEnd); pw.print(")"); 524 } 525 if (mSelectionStartIndex > MAX_INVALID_VALUE) { 526 pw.print(", selection("); pw.print(mSelectionStartIndex); 527 pw.print(", "); pw.print(mSelectionEndIndex); pw.print(")"); 528 } 529 } 530 531 @NonNull 532 @Override toString()533 public String toString() { 534 final StringBuilder string = new StringBuilder("ContentCaptureEvent[type=") 535 .append(getTypeAsString(mType)); 536 string.append(", session=").append(mSessionId); 537 if (mType == TYPE_SESSION_STARTED && mParentSessionId != NO_SESSION_ID) { 538 string.append(", parent=").append(mParentSessionId); 539 } 540 if (mId != null) { 541 string.append(", id=").append(mId); 542 } 543 if (mIds != null) { 544 string.append(", ids=").append(mIds); 545 } 546 if (mNode != null) { 547 final String className = mNode.getClassName(); 548 string.append(", class=").append(className); 549 string.append(", id=").append(mNode.getAutofillId()); 550 if (mNode.getText() != null) { 551 string.append(", text=") 552 .append(DEBUG ? mNode.getText() : getSanitizedString(mNode.getText())); 553 } 554 } 555 if (mText != null) { 556 string.append(", text=") 557 .append(DEBUG ? mText : getSanitizedString(mText)); 558 } 559 if (mClientContext != null) { 560 string.append(", context=").append(mClientContext); 561 } 562 if (mInsets != null) { 563 string.append(", insets=").append(mInsets); 564 } 565 if (mBounds != null) { 566 string.append(", bounds=").append(mBounds); 567 } 568 if (mComposingStart > MAX_INVALID_VALUE) { 569 string.append(", composing=[") 570 .append(mComposingStart).append(",").append(mComposingEnd).append("]"); 571 } 572 if (mSelectionStartIndex > MAX_INVALID_VALUE) { 573 string.append(", selection=[") 574 .append(mSelectionStartIndex).append(",") 575 .append(mSelectionEndIndex).append("]"); 576 } 577 return string.append(']').toString(); 578 } 579 580 @Override describeContents()581 public int describeContents() { 582 return 0; 583 } 584 585 @Override writeToParcel(Parcel parcel, int flags)586 public void writeToParcel(Parcel parcel, int flags) { 587 parcel.writeInt(mSessionId); 588 parcel.writeInt(mType); 589 parcel.writeLong(mEventTime); 590 parcel.writeParcelable(mId, flags); 591 parcel.writeTypedList(mIds); 592 ViewNode.writeToParcel(parcel, mNode, flags); 593 parcel.writeCharSequence(mText); 594 if (mType == TYPE_SESSION_STARTED || mType == TYPE_SESSION_FINISHED) { 595 parcel.writeInt(mParentSessionId); 596 } 597 if (mType == TYPE_SESSION_STARTED || mType == TYPE_CONTEXT_UPDATED) { 598 parcel.writeParcelable(mClientContext, flags); 599 } 600 if (mType == TYPE_VIEW_INSETS_CHANGED) { 601 parcel.writeParcelable(mInsets, flags); 602 } 603 if (mType == TYPE_WINDOW_BOUNDS_CHANGED) { 604 parcel.writeParcelable(mBounds, flags); 605 } 606 if (mType == TYPE_VIEW_TEXT_CHANGED) { 607 parcel.writeInt(mComposingStart); 608 parcel.writeInt(mComposingEnd); 609 parcel.writeInt(mSelectionStartIndex); 610 parcel.writeInt(mSelectionEndIndex); 611 } 612 } 613 614 public static final @android.annotation.NonNull Parcelable.Creator<ContentCaptureEvent> CREATOR = 615 new Parcelable.Creator<ContentCaptureEvent>() { 616 617 @Override 618 @NonNull 619 public ContentCaptureEvent createFromParcel(Parcel parcel) { 620 final int sessionId = parcel.readInt(); 621 final int type = parcel.readInt(); 622 final long eventTime = parcel.readLong(); 623 final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, type, eventTime); 624 final AutofillId id = parcel.readParcelable(null); 625 if (id != null) { 626 event.setAutofillId(id); 627 } 628 final ArrayList<AutofillId> ids = parcel.createTypedArrayList(AutofillId.CREATOR); 629 if (ids != null) { 630 event.setAutofillIds(ids); 631 } 632 final ViewNode node = ViewNode.readFromParcel(parcel); 633 if (node != null) { 634 event.setViewNode(node); 635 } 636 event.setText(parcel.readCharSequence()); 637 if (type == TYPE_SESSION_STARTED || type == TYPE_SESSION_FINISHED) { 638 event.setParentSessionId(parcel.readInt()); 639 } 640 if (type == TYPE_SESSION_STARTED || type == TYPE_CONTEXT_UPDATED) { 641 event.setClientContext(parcel.readParcelable(null)); 642 } 643 if (type == TYPE_VIEW_INSETS_CHANGED) { 644 event.setInsets(parcel.readParcelable(null)); 645 } 646 if (type == TYPE_WINDOW_BOUNDS_CHANGED) { 647 event.setBounds(parcel.readParcelable(null)); 648 } 649 if (type == TYPE_VIEW_TEXT_CHANGED) { 650 event.setComposingIndex(parcel.readInt(), parcel.readInt()); 651 event.restoreComposingSpan(); 652 event.setSelectionIndex(parcel.readInt(), parcel.readInt()); 653 event.restoreSelectionSpans(); 654 } 655 return event; 656 } 657 658 @Override 659 @NonNull 660 public ContentCaptureEvent[] newArray(int size) { 661 return new ContentCaptureEvent[size]; 662 } 663 }; 664 665 /** @hide */ getTypeAsString(@ventType int type)666 public static String getTypeAsString(@EventType int type) { 667 switch (type) { 668 case TYPE_SESSION_STARTED: 669 return "SESSION_STARTED"; 670 case TYPE_SESSION_FINISHED: 671 return "SESSION_FINISHED"; 672 case TYPE_SESSION_RESUMED: 673 return "SESSION_RESUMED"; 674 case TYPE_SESSION_PAUSED: 675 return "SESSION_PAUSED"; 676 case TYPE_VIEW_APPEARED: 677 return "VIEW_APPEARED"; 678 case TYPE_VIEW_DISAPPEARED: 679 return "VIEW_DISAPPEARED"; 680 case TYPE_VIEW_TEXT_CHANGED: 681 return "VIEW_TEXT_CHANGED"; 682 case TYPE_VIEW_TREE_APPEARING: 683 return "VIEW_TREE_APPEARING"; 684 case TYPE_VIEW_TREE_APPEARED: 685 return "VIEW_TREE_APPEARED"; 686 case TYPE_CONTEXT_UPDATED: 687 return "CONTEXT_UPDATED"; 688 case TYPE_VIEW_INSETS_CHANGED: 689 return "VIEW_INSETS_CHANGED"; 690 case TYPE_WINDOW_BOUNDS_CHANGED: 691 return "TYPE_WINDOW_BOUNDS_CHANGED"; 692 default: 693 return "UKNOWN_TYPE: " + type; 694 } 695 } 696 } 697