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