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