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 com.android.internal.util.Preconditions; 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); 128 } 129 if ((nodeFlags & FLAGS_HAS_AUTOFILL_PARENT_ID) != 0) { 130 mParentAutofillId = parcel.readParcelable(null); 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); 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); 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 writeSelfToParcel(@onNull Parcel parcel, int parcelFlags)483 private void writeSelfToParcel(@NonNull Parcel parcel, int parcelFlags) { 484 long nodeFlags = mFlags; 485 486 if (mAutofillId != null) { 487 nodeFlags |= FLAGS_HAS_AUTOFILL_ID; 488 } 489 490 if (mParentAutofillId != null) { 491 nodeFlags |= FLAGS_HAS_AUTOFILL_PARENT_ID; 492 } 493 494 if (mText != null) { 495 nodeFlags |= FLAGS_HAS_TEXT; 496 if (!mText.isSimple()) { 497 nodeFlags |= FLAGS_HAS_COMPLEX_TEXT; 498 } 499 } 500 if (mClassName != null) { 501 nodeFlags |= FLAGS_HAS_CLASSNAME; 502 } 503 if (mId != View.NO_ID) { 504 nodeFlags |= FLAGS_HAS_ID; 505 } 506 if ((mX & ~0x7fff) != 0 || (mY & ~0x7fff) != 0 507 || (mWidth & ~0x7fff) != 0 | (mHeight & ~0x7fff) != 0) { 508 nodeFlags |= FLAGS_HAS_LARGE_COORDS; 509 } 510 if (mScrollX != 0 || mScrollY != 0) { 511 nodeFlags |= FLAGS_HAS_SCROLL; 512 } 513 if (mContentDescription != null) { 514 nodeFlags |= FLAGS_HAS_CONTENT_DESCRIPTION; 515 } 516 if (mExtras != null) { 517 nodeFlags |= FLAGS_HAS_EXTRAS; 518 } 519 if (mLocaleList != null) { 520 nodeFlags |= FLAGS_HAS_LOCALE_LIST; 521 } 522 if (mReceiveContentMimeTypes != null) { 523 nodeFlags |= FLAGS_HAS_MIME_TYPES; 524 } 525 if (mInputType != 0) { 526 nodeFlags |= FLAGS_HAS_INPUT_TYPE; 527 } 528 if (mMinEms > -1) { 529 nodeFlags |= FLAGS_HAS_MIN_TEXT_EMS; 530 } 531 if (mMaxEms > -1) { 532 nodeFlags |= FLAGS_HAS_MAX_TEXT_EMS; 533 } 534 if (mMaxLength > -1) { 535 nodeFlags |= FLAGS_HAS_MAX_TEXT_LENGTH; 536 } 537 if (mTextIdEntry != null) { 538 nodeFlags |= FLAGS_HAS_TEXT_ID_ENTRY; 539 } 540 if (mAutofillValue != null) { 541 nodeFlags |= FLAGS_HAS_AUTOFILL_VALUE; 542 } 543 if (mAutofillType != View.AUTOFILL_TYPE_NONE) { 544 nodeFlags |= FLAGS_HAS_AUTOFILL_TYPE; 545 } 546 if (mAutofillHints != null) { 547 nodeFlags |= FLAGS_HAS_AUTOFILL_HINTS; 548 } 549 if (mAutofillOptions != null) { 550 nodeFlags |= FLAGS_HAS_AUTOFILL_OPTIONS; 551 } 552 if (mHintIdEntry != null) { 553 nodeFlags |= FLAGS_HAS_HINT_ID_ENTRY; 554 } 555 parcel.writeLong(nodeFlags); 556 557 if ((nodeFlags & FLAGS_HAS_AUTOFILL_ID) != 0) { 558 parcel.writeParcelable(mAutofillId, parcelFlags); 559 } 560 if ((nodeFlags & FLAGS_HAS_AUTOFILL_PARENT_ID) != 0) { 561 parcel.writeParcelable(mParentAutofillId, parcelFlags); 562 } 563 if ((nodeFlags & FLAGS_HAS_TEXT) != 0) { 564 mText.writeToParcel(parcel, (nodeFlags & FLAGS_HAS_COMPLEX_TEXT) == 0); 565 } 566 if ((nodeFlags & FLAGS_HAS_CLASSNAME) != 0) { 567 parcel.writeString(mClassName); 568 } 569 if ((nodeFlags & FLAGS_HAS_ID) != 0) { 570 parcel.writeInt(mId); 571 if (mId != View.NO_ID) { 572 parcel.writeString(mIdEntry); 573 if (mIdEntry != null) { 574 parcel.writeString(mIdType); 575 parcel.writeString(mIdPackage); 576 } 577 } 578 } 579 if ((nodeFlags & FLAGS_HAS_LARGE_COORDS) != 0) { 580 parcel.writeInt(mX); 581 parcel.writeInt(mY); 582 parcel.writeInt(mWidth); 583 parcel.writeInt(mHeight); 584 } else { 585 parcel.writeInt((mY << 16) | mX); 586 parcel.writeInt((mHeight << 16) | mWidth); 587 } 588 if ((nodeFlags & FLAGS_HAS_SCROLL) != 0) { 589 parcel.writeInt(mScrollX); 590 parcel.writeInt(mScrollY); 591 } 592 if ((nodeFlags & FLAGS_HAS_CONTENT_DESCRIPTION) != 0) { 593 TextUtils.writeToParcel(mContentDescription, parcel, 0); 594 } 595 if ((nodeFlags & FLAGS_HAS_EXTRAS) != 0) { 596 parcel.writeBundle(mExtras); 597 } 598 if ((nodeFlags & FLAGS_HAS_LOCALE_LIST) != 0) { 599 parcel.writeParcelable(mLocaleList, 0); 600 } 601 if ((nodeFlags & FLAGS_HAS_MIME_TYPES) != 0) { 602 parcel.writeStringArray(mReceiveContentMimeTypes); 603 } 604 if ((nodeFlags & FLAGS_HAS_INPUT_TYPE) != 0) { 605 parcel.writeInt(mInputType); 606 } 607 if ((nodeFlags & FLAGS_HAS_MIN_TEXT_EMS) != 0) { 608 parcel.writeInt(mMinEms); 609 } 610 if ((nodeFlags & FLAGS_HAS_MAX_TEXT_EMS) != 0) { 611 parcel.writeInt(mMaxEms); 612 } 613 if ((nodeFlags & FLAGS_HAS_MAX_TEXT_LENGTH) != 0) { 614 parcel.writeInt(mMaxLength); 615 } 616 if ((nodeFlags & FLAGS_HAS_TEXT_ID_ENTRY) != 0) { 617 parcel.writeString(mTextIdEntry); 618 } 619 if ((nodeFlags & FLAGS_HAS_AUTOFILL_TYPE) != 0) { 620 parcel.writeInt(mAutofillType); 621 } 622 if ((nodeFlags & FLAGS_HAS_AUTOFILL_HINTS) != 0) { 623 parcel.writeStringArray(mAutofillHints); 624 } 625 if ((nodeFlags & FLAGS_HAS_AUTOFILL_VALUE) != 0) { 626 parcel.writeParcelable(mAutofillValue, 0); 627 } 628 if ((nodeFlags & FLAGS_HAS_AUTOFILL_OPTIONS) != 0) { 629 parcel.writeCharSequenceArray(mAutofillOptions); 630 } 631 if ((nodeFlags & FLAGS_HAS_HINT_ID_ENTRY) != 0) { 632 parcel.writeString(mHintIdEntry); 633 } 634 } 635 636 /** @hide */ 637 @TestApi writeToParcel(@onNull Parcel parcel, @Nullable ViewNode node, int flags)638 public static void writeToParcel(@NonNull Parcel parcel, @Nullable ViewNode node, int flags) { 639 if (node == null) { 640 parcel.writeLong(0); 641 } else { 642 node.writeSelfToParcel(parcel, flags); 643 } 644 } 645 646 /** @hide */ 647 @TestApi readFromParcel(@onNull Parcel parcel)648 public static @Nullable ViewNode readFromParcel(@NonNull Parcel parcel) { 649 final long nodeFlags = parcel.readLong(); 650 return nodeFlags == 0 ? null : new ViewNode(nodeFlags, parcel); 651 } 652 653 /** @hide */ 654 @TestApi 655 public static final class ViewStructureImpl extends ViewStructure { 656 657 final ViewNode mNode = new ViewNode(); 658 659 /** @hide */ 660 @TestApi ViewStructureImpl(@onNull View view)661 public ViewStructureImpl(@NonNull View view) { 662 mNode.mAutofillId = Preconditions.checkNotNull(view).getAutofillId(); 663 final ViewParent parent = view.getParent(); 664 if (parent instanceof View) { 665 mNode.mParentAutofillId = ((View) parent).getAutofillId(); 666 } 667 } 668 669 /** @hide */ 670 @TestApi ViewStructureImpl(@onNull AutofillId parentId, long virtualId, int sessionId)671 public ViewStructureImpl(@NonNull AutofillId parentId, long virtualId, int sessionId) { 672 mNode.mParentAutofillId = Preconditions.checkNotNull(parentId); 673 mNode.mAutofillId = new AutofillId(parentId, virtualId, sessionId); 674 } 675 676 /** @hide */ 677 @TestApi getNode()678 public ViewNode getNode() { 679 return mNode; 680 } 681 682 @Override setId(int id, String packageName, String typeName, String entryName)683 public void setId(int id, String packageName, String typeName, String entryName) { 684 mNode.mId = id; 685 mNode.mIdPackage = packageName; 686 mNode.mIdType = typeName; 687 mNode.mIdEntry = entryName; 688 } 689 690 @Override setDimens(int left, int top, int scrollX, int scrollY, int width, int height)691 public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) { 692 mNode.mX = left; 693 mNode.mY = top; 694 mNode.mScrollX = scrollX; 695 mNode.mScrollY = scrollY; 696 mNode.mWidth = width; 697 mNode.mHeight = height; 698 } 699 700 @Override setTransformation(Matrix matrix)701 public void setTransformation(Matrix matrix) { 702 Log.w(TAG, "setTransformation() is not supported"); 703 } 704 705 @Override setElevation(float elevation)706 public void setElevation(float elevation) { 707 Log.w(TAG, "setElevation() is not supported"); 708 } 709 710 @Override setAlpha(float alpha)711 public void setAlpha(float alpha) { 712 Log.w(TAG, "setAlpha() is not supported"); 713 } 714 715 @Override setVisibility(int visibility)716 public void setVisibility(int visibility) { 717 mNode.mFlags = (mNode.mFlags & ~FLAGS_VISIBILITY_MASK) 718 | (visibility & FLAGS_VISIBILITY_MASK); 719 } 720 721 @Override setAssistBlocked(boolean state)722 public void setAssistBlocked(boolean state) { 723 mNode.mFlags = (mNode.mFlags & ~FLAGS_ASSIST_BLOCKED) 724 | (state ? FLAGS_ASSIST_BLOCKED : 0); 725 } 726 727 @Override setEnabled(boolean state)728 public void setEnabled(boolean state) { 729 mNode.mFlags = (mNode.mFlags & ~FLAGS_DISABLED) | (state ? 0 : FLAGS_DISABLED); 730 } 731 732 @Override setClickable(boolean state)733 public void setClickable(boolean state) { 734 mNode.mFlags = (mNode.mFlags & ~FLAGS_CLICKABLE) | (state ? FLAGS_CLICKABLE : 0); 735 } 736 737 @Override setLongClickable(boolean state)738 public void setLongClickable(boolean state) { 739 mNode.mFlags = (mNode.mFlags & ~FLAGS_LONG_CLICKABLE) 740 | (state ? FLAGS_LONG_CLICKABLE : 0); 741 } 742 743 @Override setContextClickable(boolean state)744 public void setContextClickable(boolean state) { 745 mNode.mFlags = (mNode.mFlags & ~FLAGS_CONTEXT_CLICKABLE) 746 | (state ? FLAGS_CONTEXT_CLICKABLE : 0); 747 } 748 749 @Override setFocusable(boolean state)750 public void setFocusable(boolean state) { 751 mNode.mFlags = (mNode.mFlags & ~FLAGS_FOCUSABLE) | (state ? FLAGS_FOCUSABLE : 0); 752 } 753 754 @Override setFocused(boolean state)755 public void setFocused(boolean state) { 756 mNode.mFlags = (mNode.mFlags & ~FLAGS_FOCUSED) | (state ? FLAGS_FOCUSED : 0); 757 } 758 759 @Override setAccessibilityFocused(boolean state)760 public void setAccessibilityFocused(boolean state) { 761 mNode.mFlags = (mNode.mFlags & ~FLAGS_ACCESSIBILITY_FOCUSED) 762 | (state ? FLAGS_ACCESSIBILITY_FOCUSED : 0); 763 } 764 765 @Override setCheckable(boolean state)766 public void setCheckable(boolean state) { 767 mNode.mFlags = (mNode.mFlags & ~FLAGS_CHECKABLE) | (state ? FLAGS_CHECKABLE : 0); 768 } 769 770 @Override setChecked(boolean state)771 public void setChecked(boolean state) { 772 mNode.mFlags = (mNode.mFlags & ~FLAGS_CHECKED) | (state ? FLAGS_CHECKED : 0); 773 } 774 775 @Override setSelected(boolean state)776 public void setSelected(boolean state) { 777 mNode.mFlags = (mNode.mFlags & ~FLAGS_SELECTED) | (state ? FLAGS_SELECTED : 0); 778 } 779 780 @Override setActivated(boolean state)781 public void setActivated(boolean state) { 782 mNode.mFlags = (mNode.mFlags & ~FLAGS_ACTIVATED) | (state ? FLAGS_ACTIVATED : 0); 783 } 784 785 @Override setOpaque(boolean opaque)786 public void setOpaque(boolean opaque) { 787 mNode.mFlags = (mNode.mFlags & ~FLAGS_OPAQUE) | (opaque ? FLAGS_OPAQUE : 0); 788 } 789 790 @Override setClassName(String className)791 public void setClassName(String className) { 792 mNode.mClassName = className; 793 } 794 795 @Override setContentDescription(CharSequence contentDescription)796 public void setContentDescription(CharSequence contentDescription) { 797 mNode.mContentDescription = contentDescription; 798 } 799 800 @Override setText(CharSequence text)801 public void setText(CharSequence text) { 802 final ViewNodeText t = getNodeText(); 803 t.mText = TextUtils.trimNoCopySpans(text); 804 t.mTextSelectionStart = t.mTextSelectionEnd = -1; 805 } 806 807 @Override setText(CharSequence text, int selectionStart, int selectionEnd)808 public void setText(CharSequence text, int selectionStart, int selectionEnd) { 809 final ViewNodeText t = getNodeText(); 810 t.mText = TextUtils.trimNoCopySpans(text); 811 t.mTextSelectionStart = selectionStart; 812 t.mTextSelectionEnd = selectionEnd; 813 } 814 815 @Override setTextStyle(float size, int fgColor, int bgColor, int style)816 public void setTextStyle(float size, int fgColor, int bgColor, int style) { 817 final ViewNodeText t = getNodeText(); 818 t.mTextColor = fgColor; 819 t.mTextBackgroundColor = bgColor; 820 t.mTextSize = size; 821 t.mTextStyle = style; 822 } 823 824 @Override setTextLines(int[] charOffsets, int[] baselines)825 public void setTextLines(int[] charOffsets, int[] baselines) { 826 final ViewNodeText t = getNodeText(); 827 t.mLineCharOffsets = charOffsets; 828 t.mLineBaselines = baselines; 829 } 830 831 @Override setTextIdEntry(@onNull String entryName)832 public void setTextIdEntry(@NonNull String entryName) { 833 mNode.mTextIdEntry = Preconditions.checkNotNull(entryName); 834 } 835 836 @Override setHint(CharSequence hint)837 public void setHint(CharSequence hint) { 838 getNodeText().mHint = hint != null ? hint.toString() : null; 839 } 840 841 @Override setHintIdEntry(String entryName)842 public void setHintIdEntry(String entryName) { 843 mNode.mHintIdEntry = Preconditions.checkNotNull(entryName); 844 } 845 846 @Override getText()847 public CharSequence getText() { 848 return mNode.getText(); 849 } 850 851 @Override getTextSelectionStart()852 public int getTextSelectionStart() { 853 return mNode.getTextSelectionStart(); 854 } 855 856 @Override getTextSelectionEnd()857 public int getTextSelectionEnd() { 858 return mNode.getTextSelectionEnd(); 859 } 860 861 @Override getHint()862 public CharSequence getHint() { 863 return mNode.getHint(); 864 } 865 866 @Override getExtras()867 public Bundle getExtras() { 868 if (mNode.mExtras != null) { 869 return mNode.mExtras; 870 } 871 mNode.mExtras = new Bundle(); 872 return mNode.mExtras; 873 } 874 875 @Override hasExtras()876 public boolean hasExtras() { 877 return mNode.mExtras != null; 878 } 879 880 @Override setChildCount(int num)881 public void setChildCount(int num) { 882 Log.w(TAG, "setChildCount() is not supported"); 883 } 884 885 @Override addChildCount(int num)886 public int addChildCount(int num) { 887 Log.w(TAG, "addChildCount() is not supported"); 888 return 0; 889 } 890 891 @Override getChildCount()892 public int getChildCount() { 893 Log.w(TAG, "getChildCount() is not supported"); 894 return 0; 895 } 896 897 @Override newChild(int index)898 public ViewStructure newChild(int index) { 899 Log.w(TAG, "newChild() is not supported"); 900 return null; 901 } 902 903 @Override asyncNewChild(int index)904 public ViewStructure asyncNewChild(int index) { 905 Log.w(TAG, "asyncNewChild() is not supported"); 906 return null; 907 } 908 909 @Override getAutofillId()910 public AutofillId getAutofillId() { 911 return mNode.mAutofillId; 912 } 913 914 @Override setAutofillId(AutofillId id)915 public void setAutofillId(AutofillId id) { 916 mNode.mAutofillId = Preconditions.checkNotNull(id); 917 } 918 919 920 @Override setAutofillId(AutofillId parentId, int virtualId)921 public void setAutofillId(AutofillId parentId, int virtualId) { 922 mNode.mParentAutofillId = Preconditions.checkNotNull(parentId); 923 mNode.mAutofillId = new AutofillId(parentId, virtualId); 924 } 925 926 @Override setAutofillType(@iew.AutofillType int type)927 public void setAutofillType(@View.AutofillType int type) { 928 mNode.mAutofillType = type; 929 } 930 931 @Override setReceiveContentMimeTypes(@ullable String[] mimeTypes)932 public void setReceiveContentMimeTypes(@Nullable String[] mimeTypes) { 933 mNode.mReceiveContentMimeTypes = mimeTypes; 934 } 935 936 @Override setAutofillHints(String[] hints)937 public void setAutofillHints(String[] hints) { 938 mNode.mAutofillHints = hints; 939 } 940 941 @Override setAutofillValue(AutofillValue value)942 public void setAutofillValue(AutofillValue value) { 943 mNode.mAutofillValue = value; 944 } 945 946 @Override setAutofillOptions(CharSequence[] options)947 public void setAutofillOptions(CharSequence[] options) { 948 mNode.mAutofillOptions = options; 949 } 950 951 @Override setInputType(int inputType)952 public void setInputType(int inputType) { 953 mNode.mInputType = inputType; 954 } 955 956 @Override setMinTextEms(int minEms)957 public void setMinTextEms(int minEms) { 958 mNode.mMinEms = minEms; 959 } 960 961 @Override setMaxTextEms(int maxEms)962 public void setMaxTextEms(int maxEms) { 963 mNode.mMaxEms = maxEms; 964 } 965 966 @Override setMaxTextLength(int maxLength)967 public void setMaxTextLength(int maxLength) { 968 mNode.mMaxLength = maxLength; 969 } 970 971 @Override setDataIsSensitive(boolean sensitive)972 public void setDataIsSensitive(boolean sensitive) { 973 Log.w(TAG, "setDataIsSensitive() is not supported"); 974 } 975 976 @Override asyncCommit()977 public void asyncCommit() { 978 Log.w(TAG, "asyncCommit() is not supported"); 979 } 980 981 @Override getTempRect()982 public Rect getTempRect() { 983 Log.w(TAG, "getTempRect() is not supported"); 984 return null; 985 } 986 987 @Override setWebDomain(String domain)988 public void setWebDomain(String domain) { 989 Log.w(TAG, "setWebDomain() is not supported"); 990 } 991 992 @Override setLocaleList(LocaleList localeList)993 public void setLocaleList(LocaleList localeList) { 994 mNode.mLocaleList = localeList; 995 } 996 997 @Override newHtmlInfoBuilder(String tagName)998 public Builder newHtmlInfoBuilder(String tagName) { 999 Log.w(TAG, "newHtmlInfoBuilder() is not supported"); 1000 return null; 1001 } 1002 1003 @Override setHtmlInfo(HtmlInfo htmlInfo)1004 public void setHtmlInfo(HtmlInfo htmlInfo) { 1005 Log.w(TAG, "setHtmlInfo() is not supported"); 1006 } 1007 getNodeText()1008 private ViewNodeText getNodeText() { 1009 if (mNode.mText != null) { 1010 return mNode.mText; 1011 } 1012 mNode.mText = new ViewNodeText(); 1013 return mNode.mText; 1014 } 1015 } 1016 1017 //TODO(b/122484602): copied 'as-is' from AssistStructure, except for writeSensitive 1018 static final class ViewNodeText { 1019 CharSequence mText; 1020 float mTextSize; 1021 int mTextStyle; 1022 int mTextColor = ViewNode.TEXT_COLOR_UNDEFINED; 1023 int mTextBackgroundColor = ViewNode.TEXT_COLOR_UNDEFINED; 1024 int mTextSelectionStart; 1025 int mTextSelectionEnd; 1026 int[] mLineCharOffsets; 1027 int[] mLineBaselines; 1028 String mHint; 1029 ViewNodeText()1030 ViewNodeText() { 1031 } 1032 isSimple()1033 boolean isSimple() { 1034 return mTextBackgroundColor == ViewNode.TEXT_COLOR_UNDEFINED 1035 && mTextSelectionStart == 0 && mTextSelectionEnd == 0 1036 && mLineCharOffsets == null && mLineBaselines == null && mHint == null; 1037 } 1038 ViewNodeText(Parcel in, boolean simple)1039 ViewNodeText(Parcel in, boolean simple) { 1040 mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 1041 mTextSize = in.readFloat(); 1042 mTextStyle = in.readInt(); 1043 mTextColor = in.readInt(); 1044 if (!simple) { 1045 mTextBackgroundColor = in.readInt(); 1046 mTextSelectionStart = in.readInt(); 1047 mTextSelectionEnd = in.readInt(); 1048 mLineCharOffsets = in.createIntArray(); 1049 mLineBaselines = in.createIntArray(); 1050 mHint = in.readString(); 1051 } 1052 } 1053 writeToParcel(Parcel out, boolean simple)1054 void writeToParcel(Parcel out, boolean simple) { 1055 TextUtils.writeToParcel(mText, out, 0); 1056 out.writeFloat(mTextSize); 1057 out.writeInt(mTextStyle); 1058 out.writeInt(mTextColor); 1059 if (!simple) { 1060 out.writeInt(mTextBackgroundColor); 1061 out.writeInt(mTextSelectionStart); 1062 out.writeInt(mTextSelectionEnd); 1063 out.writeIntArray(mLineCharOffsets); 1064 out.writeIntArray(mLineBaselines); 1065 out.writeString(mHint); 1066 } 1067 } 1068 } 1069 } 1070