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