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 android.annotation.NonNull; 19 import android.annotation.Nullable; 20 import android.annotation.SystemApi; 21 import android.annotation.TestApi; 22 import android.app.assist.AssistStructure; 23 import android.graphics.Matrix; 24 import android.graphics.Rect; 25 import android.os.Bundle; 26 import android.os.LocaleList; 27 import android.os.Parcel; 28 import android.text.TextUtils; 29 import android.util.Log; 30 import android.view.View; 31 import android.view.ViewParent; 32 import android.view.ViewStructure; 33 import android.view.ViewStructure.HtmlInfo.Builder; 34 import android.view.autofill.AutofillId; 35 import android.view.autofill.AutofillValue; 36 37 import java.util.Objects; 38 39 //TODO(b/122484602): add javadocs / implement Parcelable / implement 40 //TODO(b/122484602): for now it's extending ViewNode directly as it needs most of its properties, 41 // but it might be better to create a common, abstract android.view.ViewNode class that both extend 42 // instead 43 /** @hide */ 44 @SystemApi 45 public final class ViewNode extends AssistStructure.ViewNode { 46 47 private static final String TAG = ViewNode.class.getSimpleName(); 48 49 private static final long FLAGS_HAS_TEXT = 1L << 0; 50 private static final long FLAGS_HAS_COMPLEX_TEXT = 1L << 1; 51 private static final long FLAGS_VISIBILITY_MASK = View.VISIBLE | View.INVISIBLE | View.GONE; 52 private static final long FLAGS_HAS_CLASSNAME = 1L << 4; 53 private static final long FLAGS_HAS_AUTOFILL_ID = 1L << 5; 54 private static final long FLAGS_HAS_AUTOFILL_PARENT_ID = 1L << 6; 55 private static final long FLAGS_HAS_ID = 1L << 7; 56 private static final long FLAGS_HAS_LARGE_COORDS = 1L << 8; 57 private static final long FLAGS_HAS_SCROLL = 1L << 9; 58 private static final long FLAGS_ASSIST_BLOCKED = 1L << 10; 59 private static final long FLAGS_DISABLED = 1L << 11; 60 private static final long FLAGS_CLICKABLE = 1L << 12; 61 private static final long FLAGS_LONG_CLICKABLE = 1L << 13; 62 private static final long FLAGS_CONTEXT_CLICKABLE = 1L << 14; 63 private static final long FLAGS_FOCUSABLE = 1L << 15; 64 private static final long FLAGS_FOCUSED = 1L << 16; 65 private static final long FLAGS_ACCESSIBILITY_FOCUSED = 1L << 17; 66 private static final long FLAGS_CHECKABLE = 1L << 18; 67 private static final long FLAGS_CHECKED = 1L << 19; 68 private static final long FLAGS_SELECTED = 1L << 20; 69 private static final long FLAGS_ACTIVATED = 1L << 21; 70 private static final long FLAGS_OPAQUE = 1L << 22; 71 private static final long FLAGS_HAS_CONTENT_DESCRIPTION = 1L << 23; 72 private static final long FLAGS_HAS_EXTRAS = 1L << 24; 73 private static final long FLAGS_HAS_LOCALE_LIST = 1L << 25; 74 private static final long FLAGS_HAS_INPUT_TYPE = 1L << 26; 75 private static final long FLAGS_HAS_MIN_TEXT_EMS = 1L << 27; 76 private static final long FLAGS_HAS_MAX_TEXT_EMS = 1L << 28; 77 private static final long FLAGS_HAS_MAX_TEXT_LENGTH = 1L << 29; 78 private static final long FLAGS_HAS_TEXT_ID_ENTRY = 1L << 30; 79 private static final long FLAGS_HAS_AUTOFILL_TYPE = 1L << 31; 80 private static final long FLAGS_HAS_AUTOFILL_VALUE = 1L << 32; 81 private static final long FLAGS_HAS_AUTOFILL_HINTS = 1L << 33; 82 private static final long FLAGS_HAS_AUTOFILL_OPTIONS = 1L << 34; 83 private static final long FLAGS_HAS_HINT_ID_ENTRY = 1L << 35; 84 private static final long FLAGS_HAS_MIME_TYPES = 1L << 36; 85 86 /** Flags used to optimize what's written to the parcel */ 87 private long mFlags; 88 89 private AutofillId mParentAutofillId; 90 91 private AutofillId mAutofillId; 92 private ViewNodeText mText; 93 private String mClassName; 94 private int mId = View.NO_ID; 95 private String mIdPackage; 96 private String mIdType; 97 private String mIdEntry; 98 private int mX; 99 private int mY; 100 private int mScrollX; 101 private int mScrollY; 102 private int mWidth; 103 private int mHeight; 104 private CharSequence mContentDescription; 105 private Bundle mExtras; 106 private LocaleList mLocaleList; 107 private int mInputType; 108 private int mMinEms = -1; 109 private int mMaxEms = -1; 110 private int mMaxLength = -1; 111 private String mTextIdEntry; 112 private String mHintIdEntry; 113 private @View.AutofillType int mAutofillType = View.AUTOFILL_TYPE_NONE; 114 private String[] mAutofillHints; 115 private AutofillValue mAutofillValue; 116 private CharSequence[] mAutofillOptions; 117 private String[] mReceiveContentMimeTypes; 118 119 /** @hide */ ViewNode()120 public ViewNode() { 121 } 122 ViewNode(long nodeFlags, @NonNull Parcel parcel)123 private ViewNode(long nodeFlags, @NonNull Parcel parcel) { 124 mFlags = nodeFlags; 125 126 if ((nodeFlags & FLAGS_HAS_AUTOFILL_ID) != 0) { 127 mAutofillId = parcel.readParcelable(null, android.view.autofill.AutofillId.class); 128 } 129 if ((nodeFlags & FLAGS_HAS_AUTOFILL_PARENT_ID) != 0) { 130 mParentAutofillId = parcel.readParcelable(null, android.view.autofill.AutofillId.class); 131 } 132 if ((nodeFlags & FLAGS_HAS_TEXT) != 0) { 133 mText = new ViewNodeText(parcel, (nodeFlags & FLAGS_HAS_COMPLEX_TEXT) == 0); 134 } 135 if ((nodeFlags & FLAGS_HAS_CLASSNAME) != 0) { 136 mClassName = parcel.readString(); 137 } 138 if ((nodeFlags & FLAGS_HAS_ID) != 0) { 139 mId = parcel.readInt(); 140 if (mId != View.NO_ID) { 141 mIdEntry = parcel.readString(); 142 if (mIdEntry != null) { 143 mIdType = parcel.readString(); 144 mIdPackage = parcel.readString(); 145 } 146 } 147 } 148 if ((nodeFlags & FLAGS_HAS_LARGE_COORDS) != 0) { 149 mX = parcel.readInt(); 150 mY = parcel.readInt(); 151 mWidth = parcel.readInt(); 152 mHeight = parcel.readInt(); 153 } else { 154 int val = parcel.readInt(); 155 mX = val & 0x7fff; 156 mY = (val >> 16) & 0x7fff; 157 val = parcel.readInt(); 158 mWidth = val & 0x7fff; 159 mHeight = (val >> 16) & 0x7fff; 160 } 161 if ((nodeFlags & FLAGS_HAS_SCROLL) != 0) { 162 mScrollX = parcel.readInt(); 163 mScrollY = parcel.readInt(); 164 } 165 if ((nodeFlags & FLAGS_HAS_CONTENT_DESCRIPTION) != 0) { 166 mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 167 } 168 if ((nodeFlags & FLAGS_HAS_EXTRAS) != 0) { 169 mExtras = parcel.readBundle(); 170 } 171 if ((nodeFlags & FLAGS_HAS_LOCALE_LIST) != 0) { 172 mLocaleList = parcel.readParcelable(null, android.os.LocaleList.class); 173 } 174 if ((nodeFlags & FLAGS_HAS_MIME_TYPES) != 0) { 175 mReceiveContentMimeTypes = parcel.readStringArray(); 176 } 177 if ((nodeFlags & FLAGS_HAS_INPUT_TYPE) != 0) { 178 mInputType = parcel.readInt(); 179 } 180 if ((nodeFlags & FLAGS_HAS_MIN_TEXT_EMS) != 0) { 181 mMinEms = parcel.readInt(); 182 } 183 if ((nodeFlags & FLAGS_HAS_MAX_TEXT_EMS) != 0) { 184 mMaxEms = parcel.readInt(); 185 } 186 if ((nodeFlags & FLAGS_HAS_MAX_TEXT_LENGTH) != 0) { 187 mMaxLength = parcel.readInt(); 188 } 189 if ((nodeFlags & FLAGS_HAS_TEXT_ID_ENTRY) != 0) { 190 mTextIdEntry = parcel.readString(); 191 } 192 if ((nodeFlags & FLAGS_HAS_AUTOFILL_TYPE) != 0) { 193 mAutofillType = parcel.readInt(); 194 } 195 if ((nodeFlags & FLAGS_HAS_AUTOFILL_HINTS) != 0) { 196 mAutofillHints = parcel.readStringArray(); 197 } 198 if ((nodeFlags & FLAGS_HAS_AUTOFILL_VALUE) != 0) { 199 mAutofillValue = parcel.readParcelable(null, android.view.autofill.AutofillValue.class); 200 } 201 if ((nodeFlags & FLAGS_HAS_AUTOFILL_OPTIONS) != 0) { 202 mAutofillOptions = parcel.readCharSequenceArray(); 203 } 204 if ((nodeFlags & FLAGS_HAS_HINT_ID_ENTRY) != 0) { 205 mHintIdEntry = parcel.readString(); 206 } 207 } 208 209 /** 210 * Returns the {@link AutofillId} of this view's parent, if the parent is also part of the 211 * screen observation tree. 212 */ 213 @Nullable getParentAutofillId()214 public AutofillId getParentAutofillId() { 215 return mParentAutofillId; 216 } 217 218 @Nullable 219 @Override getAutofillId()220 public AutofillId getAutofillId() { 221 return mAutofillId; 222 } 223 224 @Nullable 225 @Override getText()226 public CharSequence getText() { 227 return mText != null ? mText.mText : null; 228 } 229 230 @Nullable 231 @Override getClassName()232 public String getClassName() { 233 return mClassName; 234 } 235 236 @Override getId()237 public int getId() { 238 return mId; 239 } 240 241 @Nullable 242 @Override getIdPackage()243 public String getIdPackage() { 244 return mIdPackage; 245 } 246 247 @Nullable 248 @Override getIdType()249 public String getIdType() { 250 return mIdType; 251 } 252 253 @Nullable 254 @Override getIdEntry()255 public String getIdEntry() { 256 return mIdEntry; 257 } 258 259 @Override getLeft()260 public int getLeft() { 261 return mX; 262 } 263 264 @Override getTop()265 public int getTop() { 266 return mY; 267 } 268 269 @Override getScrollX()270 public int getScrollX() { 271 return mScrollX; 272 } 273 274 @Override getScrollY()275 public int getScrollY() { 276 return mScrollY; 277 } 278 279 @Override getWidth()280 public int getWidth() { 281 return mWidth; 282 } 283 284 @Override getHeight()285 public int getHeight() { 286 return mHeight; 287 } 288 289 @Override isAssistBlocked()290 public boolean isAssistBlocked() { 291 return (mFlags & FLAGS_ASSIST_BLOCKED) != 0; 292 } 293 294 @Override isEnabled()295 public boolean isEnabled() { 296 return (mFlags & FLAGS_DISABLED) == 0; 297 } 298 299 @Override isClickable()300 public boolean isClickable() { 301 return (mFlags & FLAGS_CLICKABLE) != 0; 302 } 303 304 @Override isLongClickable()305 public boolean isLongClickable() { 306 return (mFlags & FLAGS_LONG_CLICKABLE) != 0; 307 } 308 309 @Override isContextClickable()310 public boolean isContextClickable() { 311 return (mFlags & FLAGS_CONTEXT_CLICKABLE) != 0; 312 } 313 314 @Override isFocusable()315 public boolean isFocusable() { 316 return (mFlags & FLAGS_FOCUSABLE) != 0; 317 } 318 319 @Override isFocused()320 public boolean isFocused() { 321 return (mFlags & FLAGS_FOCUSED) != 0; 322 } 323 324 @Override isAccessibilityFocused()325 public boolean isAccessibilityFocused() { 326 return (mFlags & FLAGS_ACCESSIBILITY_FOCUSED) != 0; 327 } 328 329 @Override isCheckable()330 public boolean isCheckable() { 331 return (mFlags & FLAGS_CHECKABLE) != 0; 332 } 333 334 @Override isChecked()335 public boolean isChecked() { 336 return (mFlags & FLAGS_CHECKED) != 0; 337 } 338 339 @Override isSelected()340 public boolean isSelected() { 341 return (mFlags & FLAGS_SELECTED) != 0; 342 } 343 344 @Override isActivated()345 public boolean isActivated() { 346 return (mFlags & FLAGS_ACTIVATED) != 0; 347 } 348 349 @Override isOpaque()350 public boolean isOpaque() { 351 return (mFlags & FLAGS_OPAQUE) != 0; 352 } 353 354 @Nullable 355 @Override getContentDescription()356 public CharSequence getContentDescription() { 357 return mContentDescription; 358 } 359 360 @Nullable 361 @Override getExtras()362 public Bundle getExtras() { 363 return mExtras; 364 } 365 366 @Nullable 367 @Override getHint()368 public String getHint() { 369 return mText != null ? mText.mHint : null; 370 } 371 372 @Nullable 373 @Override getHintIdEntry()374 public String getHintIdEntry() { 375 return mHintIdEntry; 376 } 377 378 @Override getTextSelectionStart()379 public int getTextSelectionStart() { 380 return mText != null ? mText.mTextSelectionStart : -1; 381 } 382 383 @Override getTextSelectionEnd()384 public int getTextSelectionEnd() { 385 return mText != null ? mText.mTextSelectionEnd : -1; 386 } 387 388 @Override getTextColor()389 public int getTextColor() { 390 return mText != null ? mText.mTextColor : TEXT_COLOR_UNDEFINED; 391 } 392 393 @Override getTextBackgroundColor()394 public int getTextBackgroundColor() { 395 return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED; 396 } 397 398 @Override getTextSize()399 public float getTextSize() { 400 return mText != null ? mText.mTextSize : 0; 401 } 402 403 @Override getTextStyle()404 public int getTextStyle() { 405 return mText != null ? mText.mTextStyle : 0; 406 } 407 408 @Nullable 409 @Override getTextLineCharOffsets()410 public int[] getTextLineCharOffsets() { 411 return mText != null ? mText.mLineCharOffsets : null; 412 } 413 414 @Nullable 415 @Override getTextLineBaselines()416 public int[] getTextLineBaselines() { 417 return mText != null ? mText.mLineBaselines : null; 418 } 419 420 @Override getVisibility()421 public int getVisibility() { 422 return (int) (mFlags & FLAGS_VISIBILITY_MASK); 423 } 424 425 @Override getInputType()426 public int getInputType() { 427 return mInputType; 428 } 429 430 @Override getMinTextEms()431 public int getMinTextEms() { 432 return mMinEms; 433 } 434 435 @Override getMaxTextEms()436 public int getMaxTextEms() { 437 return mMaxEms; 438 } 439 440 @Override getMaxTextLength()441 public int getMaxTextLength() { 442 return mMaxLength; 443 } 444 445 @Nullable 446 @Override getTextIdEntry()447 public String getTextIdEntry() { 448 return mTextIdEntry; 449 } 450 451 @Override getAutofillType()452 public @View.AutofillType int getAutofillType() { 453 return mAutofillType; 454 } 455 456 @Override getAutofillHints()457 @Nullable public String[] getAutofillHints() { 458 return mAutofillHints; 459 } 460 461 @Override getAutofillValue()462 @Nullable public AutofillValue getAutofillValue() { 463 return mAutofillValue; 464 } 465 466 @Override getAutofillOptions()467 @Nullable public CharSequence[] getAutofillOptions() { 468 return mAutofillOptions; 469 } 470 471 @Override 472 @Nullable getReceiveContentMimeTypes()473 public String[] getReceiveContentMimeTypes() { 474 return mReceiveContentMimeTypes; 475 } 476 477 @Nullable 478 @Override getLocaleList()479 public LocaleList getLocaleList() { 480 return mLocaleList; 481 } 482 483 /** @hide */ setTextIdEntry(@onNull String textIdEntry)484 public void setTextIdEntry(@NonNull String textIdEntry) { 485 mTextIdEntry = textIdEntry; 486 } 487 writeSelfToParcel(@onNull Parcel parcel, int parcelFlags)488 private void writeSelfToParcel(@NonNull Parcel parcel, int parcelFlags) { 489 long nodeFlags = mFlags; 490 491 if (mAutofillId != null) { 492 nodeFlags |= FLAGS_HAS_AUTOFILL_ID; 493 } 494 495 if (mParentAutofillId != null) { 496 nodeFlags |= FLAGS_HAS_AUTOFILL_PARENT_ID; 497 } 498 499 if (mText != null) { 500 nodeFlags |= FLAGS_HAS_TEXT; 501 if (!mText.isSimple()) { 502 nodeFlags |= FLAGS_HAS_COMPLEX_TEXT; 503 } 504 } 505 if (mClassName != null) { 506 nodeFlags |= FLAGS_HAS_CLASSNAME; 507 } 508 if (mId != View.NO_ID) { 509 nodeFlags |= FLAGS_HAS_ID; 510 } 511 if ((mX & ~0x7fff) != 0 || (mY & ~0x7fff) != 0 512 || (mWidth & ~0x7fff) != 0 | (mHeight & ~0x7fff) != 0) { 513 nodeFlags |= FLAGS_HAS_LARGE_COORDS; 514 } 515 if (mScrollX != 0 || mScrollY != 0) { 516 nodeFlags |= FLAGS_HAS_SCROLL; 517 } 518 if (mContentDescription != null) { 519 nodeFlags |= FLAGS_HAS_CONTENT_DESCRIPTION; 520 } 521 if (mExtras != null) { 522 nodeFlags |= FLAGS_HAS_EXTRAS; 523 } 524 if (mLocaleList != null) { 525 nodeFlags |= FLAGS_HAS_LOCALE_LIST; 526 } 527 if (mReceiveContentMimeTypes != null) { 528 nodeFlags |= FLAGS_HAS_MIME_TYPES; 529 } 530 if (mInputType != 0) { 531 nodeFlags |= FLAGS_HAS_INPUT_TYPE; 532 } 533 if (mMinEms > -1) { 534 nodeFlags |= FLAGS_HAS_MIN_TEXT_EMS; 535 } 536 if (mMaxEms > -1) { 537 nodeFlags |= FLAGS_HAS_MAX_TEXT_EMS; 538 } 539 if (mMaxLength > -1) { 540 nodeFlags |= FLAGS_HAS_MAX_TEXT_LENGTH; 541 } 542 if (mTextIdEntry != null) { 543 nodeFlags |= FLAGS_HAS_TEXT_ID_ENTRY; 544 } 545 if (mAutofillValue != null) { 546 nodeFlags |= FLAGS_HAS_AUTOFILL_VALUE; 547 } 548 if (mAutofillType != View.AUTOFILL_TYPE_NONE) { 549 nodeFlags |= FLAGS_HAS_AUTOFILL_TYPE; 550 } 551 if (mAutofillHints != null) { 552 nodeFlags |= FLAGS_HAS_AUTOFILL_HINTS; 553 } 554 if (mAutofillOptions != null) { 555 nodeFlags |= FLAGS_HAS_AUTOFILL_OPTIONS; 556 } 557 if (mHintIdEntry != null) { 558 nodeFlags |= FLAGS_HAS_HINT_ID_ENTRY; 559 } 560 parcel.writeLong(nodeFlags); 561 562 if ((nodeFlags & FLAGS_HAS_AUTOFILL_ID) != 0) { 563 parcel.writeParcelable(mAutofillId, parcelFlags); 564 } 565 if ((nodeFlags & FLAGS_HAS_AUTOFILL_PARENT_ID) != 0) { 566 parcel.writeParcelable(mParentAutofillId, parcelFlags); 567 } 568 if ((nodeFlags & FLAGS_HAS_TEXT) != 0) { 569 mText.writeToParcel(parcel, (nodeFlags & FLAGS_HAS_COMPLEX_TEXT) == 0); 570 } 571 if ((nodeFlags & FLAGS_HAS_CLASSNAME) != 0) { 572 parcel.writeString(mClassName); 573 } 574 if ((nodeFlags & FLAGS_HAS_ID) != 0) { 575 parcel.writeInt(mId); 576 if (mId != View.NO_ID) { 577 parcel.writeString(mIdEntry); 578 if (mIdEntry != null) { 579 parcel.writeString(mIdType); 580 parcel.writeString(mIdPackage); 581 } 582 } 583 } 584 if ((nodeFlags & FLAGS_HAS_LARGE_COORDS) != 0) { 585 parcel.writeInt(mX); 586 parcel.writeInt(mY); 587 parcel.writeInt(mWidth); 588 parcel.writeInt(mHeight); 589 } else { 590 parcel.writeInt((mY << 16) | mX); 591 parcel.writeInt((mHeight << 16) | mWidth); 592 } 593 if ((nodeFlags & FLAGS_HAS_SCROLL) != 0) { 594 parcel.writeInt(mScrollX); 595 parcel.writeInt(mScrollY); 596 } 597 if ((nodeFlags & FLAGS_HAS_CONTENT_DESCRIPTION) != 0) { 598 TextUtils.writeToParcel(mContentDescription, parcel, 0); 599 } 600 if ((nodeFlags & FLAGS_HAS_EXTRAS) != 0) { 601 parcel.writeBundle(mExtras); 602 } 603 if ((nodeFlags & FLAGS_HAS_LOCALE_LIST) != 0) { 604 parcel.writeParcelable(mLocaleList, 0); 605 } 606 if ((nodeFlags & FLAGS_HAS_MIME_TYPES) != 0) { 607 parcel.writeStringArray(mReceiveContentMimeTypes); 608 } 609 if ((nodeFlags & FLAGS_HAS_INPUT_TYPE) != 0) { 610 parcel.writeInt(mInputType); 611 } 612 if ((nodeFlags & FLAGS_HAS_MIN_TEXT_EMS) != 0) { 613 parcel.writeInt(mMinEms); 614 } 615 if ((nodeFlags & FLAGS_HAS_MAX_TEXT_EMS) != 0) { 616 parcel.writeInt(mMaxEms); 617 } 618 if ((nodeFlags & FLAGS_HAS_MAX_TEXT_LENGTH) != 0) { 619 parcel.writeInt(mMaxLength); 620 } 621 if ((nodeFlags & FLAGS_HAS_TEXT_ID_ENTRY) != 0) { 622 parcel.writeString(mTextIdEntry); 623 } 624 if ((nodeFlags & FLAGS_HAS_AUTOFILL_TYPE) != 0) { 625 parcel.writeInt(mAutofillType); 626 } 627 if ((nodeFlags & FLAGS_HAS_AUTOFILL_HINTS) != 0) { 628 parcel.writeStringArray(mAutofillHints); 629 } 630 if ((nodeFlags & FLAGS_HAS_AUTOFILL_VALUE) != 0) { 631 parcel.writeParcelable(mAutofillValue, 0); 632 } 633 if ((nodeFlags & FLAGS_HAS_AUTOFILL_OPTIONS) != 0) { 634 parcel.writeCharSequenceArray(mAutofillOptions); 635 } 636 if ((nodeFlags & FLAGS_HAS_HINT_ID_ENTRY) != 0) { 637 parcel.writeString(mHintIdEntry); 638 } 639 } 640 641 /** @hide */ 642 @TestApi writeToParcel(@onNull Parcel parcel, @Nullable ViewNode node, int flags)643 public static void writeToParcel(@NonNull Parcel parcel, @Nullable ViewNode node, int flags) { 644 if (node == null) { 645 parcel.writeLong(0); 646 } else { 647 node.writeSelfToParcel(parcel, flags); 648 } 649 } 650 651 /** @hide */ 652 @TestApi readFromParcel(@onNull Parcel parcel)653 public static @Nullable ViewNode readFromParcel(@NonNull Parcel parcel) { 654 final long nodeFlags = parcel.readLong(); 655 return nodeFlags == 0 ? null : new ViewNode(nodeFlags, parcel); 656 } 657 658 /** @hide */ 659 @TestApi 660 public static final class ViewStructureImpl extends ViewStructure { 661 662 final ViewNode mNode = new ViewNode(); 663 664 /** @hide */ 665 @TestApi ViewStructureImpl(@onNull View view)666 public ViewStructureImpl(@NonNull View view) { 667 mNode.mAutofillId = Objects.requireNonNull(view).getAutofillId(); 668 final ViewParent parent = view.getParent(); 669 if (parent instanceof View) { 670 mNode.mParentAutofillId = ((View) parent).getAutofillId(); 671 } 672 } 673 674 /** @hide */ 675 @TestApi ViewStructureImpl(@onNull AutofillId parentId, long virtualId, int sessionId)676 public ViewStructureImpl(@NonNull AutofillId parentId, long virtualId, int sessionId) { 677 mNode.mParentAutofillId = Objects.requireNonNull(parentId); 678 mNode.mAutofillId = new AutofillId(parentId, virtualId, sessionId); 679 } 680 681 /** @hide */ 682 @TestApi getNode()683 public ViewNode getNode() { 684 return mNode; 685 } 686 687 @Override setId(int id, String packageName, String typeName, String entryName)688 public void setId(int id, String packageName, String typeName, String entryName) { 689 mNode.mId = id; 690 mNode.mIdPackage = packageName; 691 mNode.mIdType = typeName; 692 mNode.mIdEntry = entryName; 693 } 694 695 @Override setDimens(int left, int top, int scrollX, int scrollY, int width, int height)696 public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) { 697 mNode.mX = left; 698 mNode.mY = top; 699 mNode.mScrollX = scrollX; 700 mNode.mScrollY = scrollY; 701 mNode.mWidth = width; 702 mNode.mHeight = height; 703 } 704 705 @Override setTransformation(Matrix matrix)706 public void setTransformation(Matrix matrix) { 707 Log.w(TAG, "setTransformation() is not supported"); 708 } 709 710 @Override setElevation(float elevation)711 public void setElevation(float elevation) { 712 Log.w(TAG, "setElevation() is not supported"); 713 } 714 715 @Override setAlpha(float alpha)716 public void setAlpha(float alpha) { 717 Log.w(TAG, "setAlpha() is not supported"); 718 } 719 720 @Override setVisibility(int visibility)721 public void setVisibility(int visibility) { 722 mNode.mFlags = (mNode.mFlags & ~FLAGS_VISIBILITY_MASK) 723 | (visibility & FLAGS_VISIBILITY_MASK); 724 } 725 726 @Override setAssistBlocked(boolean state)727 public void setAssistBlocked(boolean state) { 728 mNode.mFlags = (mNode.mFlags & ~FLAGS_ASSIST_BLOCKED) 729 | (state ? FLAGS_ASSIST_BLOCKED : 0); 730 } 731 732 @Override setEnabled(boolean state)733 public void setEnabled(boolean state) { 734 mNode.mFlags = (mNode.mFlags & ~FLAGS_DISABLED) | (state ? 0 : FLAGS_DISABLED); 735 } 736 737 @Override setClickable(boolean state)738 public void setClickable(boolean state) { 739 mNode.mFlags = (mNode.mFlags & ~FLAGS_CLICKABLE) | (state ? FLAGS_CLICKABLE : 0); 740 } 741 742 @Override setLongClickable(boolean state)743 public void setLongClickable(boolean state) { 744 mNode.mFlags = (mNode.mFlags & ~FLAGS_LONG_CLICKABLE) 745 | (state ? FLAGS_LONG_CLICKABLE : 0); 746 } 747 748 @Override setContextClickable(boolean state)749 public void setContextClickable(boolean state) { 750 mNode.mFlags = (mNode.mFlags & ~FLAGS_CONTEXT_CLICKABLE) 751 | (state ? FLAGS_CONTEXT_CLICKABLE : 0); 752 } 753 754 @Override setFocusable(boolean state)755 public void setFocusable(boolean state) { 756 mNode.mFlags = (mNode.mFlags & ~FLAGS_FOCUSABLE) | (state ? FLAGS_FOCUSABLE : 0); 757 } 758 759 @Override setFocused(boolean state)760 public void setFocused(boolean state) { 761 mNode.mFlags = (mNode.mFlags & ~FLAGS_FOCUSED) | (state ? FLAGS_FOCUSED : 0); 762 } 763 764 @Override setAccessibilityFocused(boolean state)765 public void setAccessibilityFocused(boolean state) { 766 mNode.mFlags = (mNode.mFlags & ~FLAGS_ACCESSIBILITY_FOCUSED) 767 | (state ? FLAGS_ACCESSIBILITY_FOCUSED : 0); 768 } 769 770 @Override setCheckable(boolean state)771 public void setCheckable(boolean state) { 772 mNode.mFlags = (mNode.mFlags & ~FLAGS_CHECKABLE) | (state ? FLAGS_CHECKABLE : 0); 773 } 774 775 @Override setChecked(boolean state)776 public void setChecked(boolean state) { 777 mNode.mFlags = (mNode.mFlags & ~FLAGS_CHECKED) | (state ? FLAGS_CHECKED : 0); 778 } 779 780 @Override setSelected(boolean state)781 public void setSelected(boolean state) { 782 mNode.mFlags = (mNode.mFlags & ~FLAGS_SELECTED) | (state ? FLAGS_SELECTED : 0); 783 } 784 785 @Override setActivated(boolean state)786 public void setActivated(boolean state) { 787 mNode.mFlags = (mNode.mFlags & ~FLAGS_ACTIVATED) | (state ? FLAGS_ACTIVATED : 0); 788 } 789 790 @Override setOpaque(boolean opaque)791 public void setOpaque(boolean opaque) { 792 mNode.mFlags = (mNode.mFlags & ~FLAGS_OPAQUE) | (opaque ? FLAGS_OPAQUE : 0); 793 } 794 795 @Override setClassName(String className)796 public void setClassName(String className) { 797 mNode.mClassName = className; 798 } 799 800 @Override setContentDescription(CharSequence contentDescription)801 public void setContentDescription(CharSequence contentDescription) { 802 mNode.mContentDescription = contentDescription; 803 } 804 805 @Override setText(CharSequence text)806 public void setText(CharSequence text) { 807 final ViewNodeText t = getNodeText(); 808 t.mText = TextUtils.trimNoCopySpans(text); 809 t.mTextSelectionStart = t.mTextSelectionEnd = -1; 810 } 811 812 @Override setText(CharSequence text, int selectionStart, int selectionEnd)813 public void setText(CharSequence text, int selectionStart, int selectionEnd) { 814 final ViewNodeText t = getNodeText(); 815 t.mText = TextUtils.trimNoCopySpans(text); 816 t.mTextSelectionStart = selectionStart; 817 t.mTextSelectionEnd = selectionEnd; 818 } 819 820 @Override setTextStyle(float size, int fgColor, int bgColor, int style)821 public void setTextStyle(float size, int fgColor, int bgColor, int style) { 822 final ViewNodeText t = getNodeText(); 823 t.mTextColor = fgColor; 824 t.mTextBackgroundColor = bgColor; 825 t.mTextSize = size; 826 t.mTextStyle = style; 827 } 828 829 @Override setTextLines(int[] charOffsets, int[] baselines)830 public void setTextLines(int[] charOffsets, int[] baselines) { 831 final ViewNodeText t = getNodeText(); 832 t.mLineCharOffsets = charOffsets; 833 t.mLineBaselines = baselines; 834 } 835 836 @Override setTextIdEntry(@onNull String entryName)837 public void setTextIdEntry(@NonNull String entryName) { 838 mNode.mTextIdEntry = Objects.requireNonNull(entryName); 839 } 840 841 @Override setHint(CharSequence hint)842 public void setHint(CharSequence hint) { 843 getNodeText().mHint = hint != null ? hint.toString() : null; 844 } 845 846 @Override setHintIdEntry(String entryName)847 public void setHintIdEntry(String entryName) { 848 mNode.mHintIdEntry = Objects.requireNonNull(entryName); 849 } 850 851 @Override getText()852 public CharSequence getText() { 853 return mNode.getText(); 854 } 855 856 @Override getTextSelectionStart()857 public int getTextSelectionStart() { 858 return mNode.getTextSelectionStart(); 859 } 860 861 @Override getTextSelectionEnd()862 public int getTextSelectionEnd() { 863 return mNode.getTextSelectionEnd(); 864 } 865 866 @Override getHint()867 public CharSequence getHint() { 868 return mNode.getHint(); 869 } 870 871 @Override getExtras()872 public Bundle getExtras() { 873 if (mNode.mExtras != null) { 874 return mNode.mExtras; 875 } 876 mNode.mExtras = new Bundle(); 877 return mNode.mExtras; 878 } 879 880 @Override hasExtras()881 public boolean hasExtras() { 882 return mNode.mExtras != null; 883 } 884 885 @Override setChildCount(int num)886 public void setChildCount(int num) { 887 Log.w(TAG, "setChildCount() is not supported"); 888 } 889 890 @Override addChildCount(int num)891 public int addChildCount(int num) { 892 Log.w(TAG, "addChildCount() is not supported"); 893 return 0; 894 } 895 896 @Override getChildCount()897 public int getChildCount() { 898 Log.w(TAG, "getChildCount() is not supported"); 899 return 0; 900 } 901 902 @Override newChild(int index)903 public ViewStructure newChild(int index) { 904 Log.w(TAG, "newChild() is not supported"); 905 return null; 906 } 907 908 @Override asyncNewChild(int index)909 public ViewStructure asyncNewChild(int index) { 910 Log.w(TAG, "asyncNewChild() is not supported"); 911 return null; 912 } 913 914 @Override getAutofillId()915 public AutofillId getAutofillId() { 916 return mNode.mAutofillId; 917 } 918 919 @Override setAutofillId(AutofillId id)920 public void setAutofillId(AutofillId id) { 921 mNode.mAutofillId = Objects.requireNonNull(id); 922 } 923 924 925 @Override setAutofillId(AutofillId parentId, int virtualId)926 public void setAutofillId(AutofillId parentId, int virtualId) { 927 mNode.mParentAutofillId = Objects.requireNonNull(parentId); 928 mNode.mAutofillId = new AutofillId(parentId, virtualId); 929 } 930 931 @Override setAutofillType(@iew.AutofillType int type)932 public void setAutofillType(@View.AutofillType int type) { 933 mNode.mAutofillType = type; 934 } 935 936 @Override setReceiveContentMimeTypes(@ullable String[] mimeTypes)937 public void setReceiveContentMimeTypes(@Nullable String[] mimeTypes) { 938 mNode.mReceiveContentMimeTypes = mimeTypes; 939 } 940 941 @Override setAutofillHints(String[] hints)942 public void setAutofillHints(String[] hints) { 943 mNode.mAutofillHints = hints; 944 } 945 946 @Override setAutofillValue(AutofillValue value)947 public void setAutofillValue(AutofillValue value) { 948 mNode.mAutofillValue = value; 949 } 950 951 @Override setAutofillOptions(CharSequence[] options)952 public void setAutofillOptions(CharSequence[] options) { 953 mNode.mAutofillOptions = options; 954 } 955 956 @Override setInputType(int inputType)957 public void setInputType(int inputType) { 958 mNode.mInputType = inputType; 959 } 960 961 @Override setMinTextEms(int minEms)962 public void setMinTextEms(int minEms) { 963 mNode.mMinEms = minEms; 964 } 965 966 @Override setMaxTextEms(int maxEms)967 public void setMaxTextEms(int maxEms) { 968 mNode.mMaxEms = maxEms; 969 } 970 971 @Override setMaxTextLength(int maxLength)972 public void setMaxTextLength(int maxLength) { 973 mNode.mMaxLength = maxLength; 974 } 975 976 @Override setDataIsSensitive(boolean sensitive)977 public void setDataIsSensitive(boolean sensitive) { 978 Log.w(TAG, "setDataIsSensitive() is not supported"); 979 } 980 981 @Override asyncCommit()982 public void asyncCommit() { 983 Log.w(TAG, "asyncCommit() is not supported"); 984 } 985 986 @Override getTempRect()987 public Rect getTempRect() { 988 Log.w(TAG, "getTempRect() is not supported"); 989 return null; 990 } 991 992 @Override setWebDomain(String domain)993 public void setWebDomain(String domain) { 994 Log.w(TAG, "setWebDomain() is not supported"); 995 } 996 997 @Override setLocaleList(LocaleList localeList)998 public void setLocaleList(LocaleList localeList) { 999 mNode.mLocaleList = localeList; 1000 } 1001 1002 @Override newHtmlInfoBuilder(String tagName)1003 public Builder newHtmlInfoBuilder(String tagName) { 1004 Log.w(TAG, "newHtmlInfoBuilder() is not supported"); 1005 return null; 1006 } 1007 1008 @Override setHtmlInfo(HtmlInfo htmlInfo)1009 public void setHtmlInfo(HtmlInfo htmlInfo) { 1010 Log.w(TAG, "setHtmlInfo() is not supported"); 1011 } 1012 getNodeText()1013 private ViewNodeText getNodeText() { 1014 if (mNode.mText != null) { 1015 return mNode.mText; 1016 } 1017 mNode.mText = new ViewNodeText(); 1018 return mNode.mText; 1019 } 1020 } 1021 1022 //TODO(b/122484602): copied 'as-is' from AssistStructure, except for writeSensitive 1023 static final class ViewNodeText { 1024 CharSequence mText; 1025 float mTextSize; 1026 int mTextStyle; 1027 int mTextColor = ViewNode.TEXT_COLOR_UNDEFINED; 1028 int mTextBackgroundColor = ViewNode.TEXT_COLOR_UNDEFINED; 1029 int mTextSelectionStart; 1030 int mTextSelectionEnd; 1031 int[] mLineCharOffsets; 1032 int[] mLineBaselines; 1033 String mHint; 1034 ViewNodeText()1035 ViewNodeText() { 1036 } 1037 isSimple()1038 boolean isSimple() { 1039 return mTextBackgroundColor == ViewNode.TEXT_COLOR_UNDEFINED 1040 && mTextSelectionStart == 0 && mTextSelectionEnd == 0 1041 && mLineCharOffsets == null && mLineBaselines == null && mHint == null; 1042 } 1043 ViewNodeText(Parcel in, boolean simple)1044 ViewNodeText(Parcel in, boolean simple) { 1045 mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 1046 mTextSize = in.readFloat(); 1047 mTextStyle = in.readInt(); 1048 mTextColor = in.readInt(); 1049 if (!simple) { 1050 mTextBackgroundColor = in.readInt(); 1051 mTextSelectionStart = in.readInt(); 1052 mTextSelectionEnd = in.readInt(); 1053 mLineCharOffsets = in.createIntArray(); 1054 mLineBaselines = in.createIntArray(); 1055 mHint = in.readString(); 1056 } 1057 } 1058 writeToParcel(Parcel out, boolean simple)1059 void writeToParcel(Parcel out, boolean simple) { 1060 CharSequence text = TextUtils.trimToParcelableSize(mText); 1061 TextUtils.writeToParcel(text, out, 0); 1062 out.writeFloat(mTextSize); 1063 out.writeInt(mTextStyle); 1064 out.writeInt(mTextColor); 1065 if (!simple) { 1066 int selectionStart = text != null 1067 ? Math.min(mTextSelectionStart, text.length()) 1068 : mTextSelectionStart; 1069 int selectionEnd = text != null 1070 ? Math.min(mTextSelectionEnd, text.length()) 1071 : mTextSelectionEnd; 1072 out.writeInt(mTextBackgroundColor); 1073 out.writeInt(selectionStart); 1074 out.writeInt(selectionEnd); 1075 out.writeIntArray(mLineCharOffsets); 1076 out.writeIntArray(mLineBaselines); 1077 out.writeString(mHint); 1078 } 1079 } 1080 } 1081 } 1082