OSDN Git Service

Sanity check to avoice NPE if an app-provided URI is invalid.
[android-x86/frameworks-base.git] / core / java / android / app / assist / AssistStructure.java
1 package android.app.assist;
2
3 import android.annotation.NonNull;
4 import android.annotation.Nullable;
5 import android.app.Activity;
6 import android.content.ComponentName;
7 import android.content.Context;
8 import android.graphics.Matrix;
9 import android.graphics.Rect;
10 import android.net.Uri;
11 import android.os.BadParcelableException;
12 import android.os.Binder;
13 import android.os.Bundle;
14 import android.os.IBinder;
15 import android.os.LocaleList;
16 import android.os.Parcel;
17 import android.os.Parcelable;
18 import android.os.PooledStringReader;
19 import android.os.PooledStringWriter;
20 import android.os.RemoteException;
21 import android.os.SystemClock;
22 import android.service.autofill.FillRequest;
23 import android.text.TextUtils;
24 import android.util.Log;
25 import android.util.Pair;
26 import android.view.View;
27 import android.view.View.AutofillImportance;
28 import android.view.ViewRootImpl;
29 import android.view.ViewStructure;
30 import android.view.ViewStructure.HtmlInfo;
31 import android.view.ViewStructure.HtmlInfo.Builder;
32 import android.view.WindowManager;
33 import android.view.WindowManagerGlobal;
34 import android.view.autofill.AutofillId;
35 import android.view.autofill.AutofillValue;
36
37 import com.android.internal.util.Preconditions;
38
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.List;
42
43 /**
44  * Assist data automatically created by the platform's implementation of assist and autofill.
45  *
46  * <p>The structure is used for assist purposes when created by
47  * {@link android.app.Activity#onProvideAssistData}, {@link View#onProvideStructure(ViewStructure)},
48  * or {@link View#onProvideVirtualStructure(ViewStructure)}.
49  *
50  * <p>The structure is used for autofill purposes when created by
51  * {@link View#onProvideAutofillStructure(ViewStructure, int)},
52  * or {@link View#onProvideAutofillVirtualStructure(ViewStructure, int)}.
53  *
54  * <p>For performance reasons, some properties of the assist data might be available just for assist
55  * or autofill purposes; in those case, the property availability will be document in its javadoc.
56  */
57 public class AssistStructure implements Parcelable {
58     static final String TAG = "AssistStructure";
59
60     static final boolean DEBUG_PARCEL = false;
61     static final boolean DEBUG_PARCEL_CHILDREN = false;
62     static final boolean DEBUG_PARCEL_TREE = false;
63
64     static final int VALIDATE_WINDOW_TOKEN = 0x11111111;
65     static final int VALIDATE_VIEW_TOKEN = 0x22222222;
66
67     boolean mHaveData;
68
69     ComponentName mActivityComponent;
70     private boolean mIsHomeActivity;
71     private int mFlags;
72
73     final ArrayList<WindowNode> mWindowNodes = new ArrayList<>();
74
75     final ArrayList<ViewNodeBuilder> mPendingAsyncChildren = new ArrayList<>();
76
77     SendChannel mSendChannel;
78     IBinder mReceiveChannel;
79
80     Rect mTmpRect = new Rect();
81
82     boolean mSanitizeOnWrite = false;
83     private long mAcquisitionStartTime;
84     private long mAcquisitionEndTime;
85
86     static final int TRANSACTION_XFER = Binder.FIRST_CALL_TRANSACTION+1;
87     static final String DESCRIPTOR = "android.app.AssistStructure";
88
89     /** @hide */
90     public void setAcquisitionStartTime(long acquisitionStartTime) {
91         mAcquisitionStartTime = acquisitionStartTime;
92     }
93
94     /** @hide */
95     public void setAcquisitionEndTime(long acquisitionEndTime) {
96         mAcquisitionEndTime = acquisitionEndTime;
97     }
98
99     /**
100      * @hide
101      * Set the home activity flag.
102      */
103     public void setHomeActivity(boolean isHomeActivity) {
104         mIsHomeActivity = isHomeActivity;
105     }
106
107     /**
108      * Returns the time when the activity started generating assist data to build the
109      * AssistStructure. The time is as specified by {@link SystemClock#uptimeMillis()}.
110      *
111      * @see #getAcquisitionEndTime()
112      * @return Returns the acquisition start time of the assist data, in milliseconds.
113      */
114     public long getAcquisitionStartTime() {
115         ensureData();
116         return mAcquisitionStartTime;
117     }
118
119     /**
120      * Returns the time when the activity finished generating assist data to build the
121      * AssistStructure. The time is as specified by {@link SystemClock#uptimeMillis()}.
122      *
123      * @see #getAcquisitionStartTime()
124      * @return Returns the acquisition end time of the assist data, in milliseconds.
125      */
126     public long getAcquisitionEndTime() {
127         ensureData();
128         return mAcquisitionEndTime;
129     }
130
131     final static class SendChannel extends Binder {
132         volatile AssistStructure mAssistStructure;
133
134         SendChannel(AssistStructure as) {
135             mAssistStructure = as;
136         }
137
138         @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
139                 throws RemoteException {
140             if (code == TRANSACTION_XFER) {
141                 AssistStructure as = mAssistStructure;
142                 if (as == null) {
143                     return true;
144                 }
145
146                 data.enforceInterface(DESCRIPTOR);
147                 IBinder token = data.readStrongBinder();
148                 if (DEBUG_PARCEL) Log.d(TAG, "Request for data on " + as
149                         + " using token " + token);
150                 if (token != null) {
151                     if (DEBUG_PARCEL) Log.d(TAG, "Resuming partial write of " + token);
152                     if (token instanceof ParcelTransferWriter) {
153                         ParcelTransferWriter xfer = (ParcelTransferWriter)token;
154                         xfer.writeToParcel(as, reply);
155                         return true;
156                     }
157                     Log.w(TAG, "Caller supplied bad token type: " + token);
158                     // Don't write anything; this is the end of the data.
159                     return true;
160                 }
161                 //long start = SystemClock.uptimeMillis();
162                 ParcelTransferWriter xfer = new ParcelTransferWriter(as, reply);
163                 xfer.writeToParcel(as, reply);
164                 //Log.i(TAG, "Time to parcel: " + (SystemClock.uptimeMillis()-start) + "ms");
165                 return true;
166             } else {
167                 return super.onTransact(code, data, reply, flags);
168             }
169         }
170     }
171
172     final static class ViewStackEntry {
173         ViewNode node;
174         int curChild;
175         int numChildren;
176     }
177
178     final static class ParcelTransferWriter extends Binder {
179         final boolean mWriteStructure;
180         int mCurWindow;
181         int mNumWindows;
182         final ArrayList<ViewStackEntry> mViewStack = new ArrayList<>();
183         ViewStackEntry mCurViewStackEntry;
184         int mCurViewStackPos;
185         int mNumWrittenWindows;
186         int mNumWrittenViews;
187         final float[] mTmpMatrix = new float[9];
188         final boolean mSanitizeOnWrite;
189
190         ParcelTransferWriter(AssistStructure as, Parcel out) {
191             mSanitizeOnWrite = as.mSanitizeOnWrite;
192             mWriteStructure = as.waitForReady();
193             ComponentName.writeToParcel(as.mActivityComponent, out);
194             out.writeInt(as.mFlags);
195             out.writeLong(as.mAcquisitionStartTime);
196             out.writeLong(as.mAcquisitionEndTime);
197             mNumWindows = as.mWindowNodes.size();
198             if (mWriteStructure && mNumWindows > 0) {
199                 out.writeInt(mNumWindows);
200             } else {
201                 out.writeInt(0);
202             }
203         }
204
205         void writeToParcel(AssistStructure as, Parcel out) {
206             int start = out.dataPosition();
207             mNumWrittenWindows = 0;
208             mNumWrittenViews = 0;
209             boolean more = writeToParcelInner(as, out);
210             Log.i(TAG, "Flattened " + (more ? "partial" : "final") + " assist data: "
211                     + (out.dataPosition() - start)
212                     + " bytes, containing " + mNumWrittenWindows + " windows, "
213                     + mNumWrittenViews + " views");
214         }
215
216         boolean writeToParcelInner(AssistStructure as, Parcel out) {
217             if (mNumWindows == 0) {
218                 return false;
219             }
220             if (DEBUG_PARCEL) Log.d(TAG, "Creating PooledStringWriter @ " + out.dataPosition());
221             PooledStringWriter pwriter = new PooledStringWriter(out);
222             while (writeNextEntryToParcel(as, out, pwriter)) {
223                 // If the parcel is above the IPC limit, then we are getting too
224                 // large for a single IPC so stop here and let the caller come back when it
225                 // is ready for more.
226                 if (out.dataSize() > IBinder.MAX_IPC_SIZE) {
227                     if (DEBUG_PARCEL) Log.d(TAG, "Assist data size is " + out.dataSize()
228                             + " @ pos " + out.dataPosition() + "; returning partial result");
229                     out.writeInt(0);
230                     out.writeStrongBinder(this);
231                     if (DEBUG_PARCEL) Log.d(TAG, "Finishing PooledStringWriter @ "
232                             + out.dataPosition() + ", size " + pwriter.getStringCount());
233                     pwriter.finish();
234                     return true;
235                 }
236             }
237             if (DEBUG_PARCEL) Log.d(TAG, "Finishing PooledStringWriter @ "
238                     + out.dataPosition() + ", size " + pwriter.getStringCount());
239             pwriter.finish();
240             mViewStack.clear();
241             return false;
242         }
243
244         void pushViewStackEntry(ViewNode node, int pos) {
245             ViewStackEntry entry;
246             if (pos >= mViewStack.size()) {
247                 entry = new ViewStackEntry();
248                 mViewStack.add(entry);
249                 if (DEBUG_PARCEL_TREE) Log.d(TAG, "New stack entry at " + pos + ": " + entry);
250             } else {
251                 entry = mViewStack.get(pos);
252                 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Existing stack entry at " + pos + ": " + entry);
253             }
254             entry.node = node;
255             entry.numChildren = node.getChildCount();
256             entry.curChild = 0;
257             mCurViewStackEntry = entry;
258         }
259
260         void writeView(ViewNode child, Parcel out, PooledStringWriter pwriter, int levelAdj) {
261             if (DEBUG_PARCEL) Log.d(TAG, "write view: at " + out.dataPosition()
262                     + ", windows=" + mNumWrittenWindows
263                     + ", views=" + mNumWrittenViews
264                     + ", level=" + (mCurViewStackPos+levelAdj));
265             out.writeInt(VALIDATE_VIEW_TOKEN);
266             int flags = child.writeSelfToParcel(out, pwriter, mSanitizeOnWrite, mTmpMatrix);
267             mNumWrittenViews++;
268             // If the child has children, push it on the stack to write them next.
269             if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) {
270                 if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG,
271                         "Preparing to write " + child.mChildren.length
272                                 + " children: @ #" + mNumWrittenViews
273                                 + ", level " + (mCurViewStackPos+levelAdj));
274                 out.writeInt(child.mChildren.length);
275                 int pos = ++mCurViewStackPos;
276                 pushViewStackEntry(child, pos);
277             }
278         }
279
280         boolean writeNextEntryToParcel(AssistStructure as, Parcel out, PooledStringWriter pwriter) {
281             // Write next view node if appropriate.
282             if (mCurViewStackEntry != null) {
283                 if (mCurViewStackEntry.curChild < mCurViewStackEntry.numChildren) {
284                     // Write the next child in the current view.
285                     if (DEBUG_PARCEL_TREE) Log.d(TAG, "Writing child #"
286                             + mCurViewStackEntry.curChild + " in " + mCurViewStackEntry.node);
287                     ViewNode child = mCurViewStackEntry.node.mChildren[mCurViewStackEntry.curChild];
288                     mCurViewStackEntry.curChild++;
289                     writeView(child, out, pwriter, 1);
290                     return true;
291                 }
292
293                 // We are done writing children of the current view; pop off the stack.
294                 do {
295                     int pos = --mCurViewStackPos;
296                     if (DEBUG_PARCEL_TREE) Log.d(TAG, "Done with " + mCurViewStackEntry.node
297                             + "; popping up to " + pos);
298                     if (pos < 0) {
299                         // Reached the last view; step to next window.
300                         if (DEBUG_PARCEL_TREE) Log.d(TAG, "Done with view hierarchy!");
301                         mCurViewStackEntry = null;
302                         break;
303                     }
304                     mCurViewStackEntry = mViewStack.get(pos);
305                 } while (mCurViewStackEntry.curChild >= mCurViewStackEntry.numChildren);
306                 return true;
307             }
308
309             // Write the next window if appropriate.
310             int pos = mCurWindow;
311             if (pos < mNumWindows) {
312                 WindowNode win = as.mWindowNodes.get(pos);
313                 mCurWindow++;
314                 if (DEBUG_PARCEL) Log.d(TAG, "write window #" + pos + ": at " + out.dataPosition()
315                         + ", windows=" + mNumWrittenWindows
316                         + ", views=" + mNumWrittenViews);
317                 out.writeInt(VALIDATE_WINDOW_TOKEN);
318                 win.writeSelfToParcel(out, pwriter, mTmpMatrix);
319                 mNumWrittenWindows++;
320                 ViewNode root = win.mRoot;
321                 mCurViewStackPos = 0;
322                 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Writing initial root view " + root);
323                 writeView(root, out, pwriter, 0);
324                 return true;
325             }
326
327             return false;
328         }
329     }
330
331     final class ParcelTransferReader {
332         final float[] mTmpMatrix = new float[9];
333         PooledStringReader mStringReader;
334
335         int mNumReadWindows;
336         int mNumReadViews;
337
338         private final IBinder mChannel;
339         private IBinder mTransferToken;
340         private Parcel mCurParcel;
341
342         ParcelTransferReader(IBinder channel) {
343             mChannel = channel;
344         }
345
346         void go() {
347             fetchData();
348             mActivityComponent = ComponentName.readFromParcel(mCurParcel);
349             mFlags = mCurParcel.readInt();
350             mAcquisitionStartTime = mCurParcel.readLong();
351             mAcquisitionEndTime = mCurParcel.readLong();
352             final int N = mCurParcel.readInt();
353             if (N > 0) {
354                 if (DEBUG_PARCEL) Log.d(TAG, "Creating PooledStringReader @ "
355                         + mCurParcel.dataPosition());
356                 mStringReader = new PooledStringReader(mCurParcel);
357                 if (DEBUG_PARCEL) Log.d(TAG, "PooledStringReader size = "
358                         + mStringReader.getStringCount());
359                 for (int i=0; i<N; i++) {
360                     mWindowNodes.add(new WindowNode(this));
361                 }
362             }
363             if (DEBUG_PARCEL) Log.d(TAG, "Finished reading: at " + mCurParcel.dataPosition()
364                     + ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows
365                     + ", views=" + mNumReadViews);
366             mCurParcel.recycle();
367             mCurParcel = null; // Parcel cannot be used after recycled.
368         }
369
370         Parcel readParcel(int validateToken, int level) {
371             if (DEBUG_PARCEL) Log.d(TAG, "readParcel: at " + mCurParcel.dataPosition()
372                     + ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows
373                     + ", views=" + mNumReadViews + ", level=" + level);
374             int token = mCurParcel.readInt();
375             if (token != 0) {
376                 if (token != validateToken) {
377                     throw new BadParcelableException("Got token " + Integer.toHexString(token)
378                             + ", expected token " + Integer.toHexString(validateToken));
379                 }
380                 return mCurParcel;
381             }
382             // We have run out of partial data, need to read another batch.
383             mTransferToken = mCurParcel.readStrongBinder();
384             if (mTransferToken == null) {
385                 throw new IllegalStateException(
386                         "Reached end of partial data without transfer token");
387             }
388             if (DEBUG_PARCEL) Log.d(TAG, "Ran out of partial data at "
389                     + mCurParcel.dataPosition() + ", token " + mTransferToken);
390             fetchData();
391             if (DEBUG_PARCEL) Log.d(TAG, "Creating PooledStringReader @ "
392                     + mCurParcel.dataPosition());
393             mStringReader = new PooledStringReader(mCurParcel);
394             if (DEBUG_PARCEL) Log.d(TAG, "PooledStringReader size = "
395                     + mStringReader.getStringCount());
396             if (DEBUG_PARCEL) Log.d(TAG, "readParcel: at " + mCurParcel.dataPosition()
397                     + ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows
398                     + ", views=" + mNumReadViews);
399             mCurParcel.readInt();
400             return mCurParcel;
401         }
402
403         private void fetchData() {
404             Parcel data = Parcel.obtain();
405             try {
406                 data.writeInterfaceToken(DESCRIPTOR);
407                 data.writeStrongBinder(mTransferToken);
408                 if (DEBUG_PARCEL) Log.d(TAG, "Requesting data with token " + mTransferToken);
409                 if (mCurParcel != null) {
410                     mCurParcel.recycle();
411                 }
412                 mCurParcel = Parcel.obtain();
413                 try {
414                     mChannel.transact(TRANSACTION_XFER, data, mCurParcel, 0);
415                 } catch (RemoteException e) {
416                     Log.w(TAG, "Failure reading AssistStructure data", e);
417                     throw new IllegalStateException("Failure reading AssistStructure data: " + e);
418                 }
419             } finally {
420                 data.recycle();
421             }
422             mNumReadWindows = mNumReadViews = 0;
423         }
424     }
425
426     final static class ViewNodeText {
427         CharSequence mText;
428         float mTextSize;
429         int mTextStyle;
430         int mTextColor = ViewNode.TEXT_COLOR_UNDEFINED;
431         int mTextBackgroundColor = ViewNode.TEXT_COLOR_UNDEFINED;
432         int mTextSelectionStart;
433         int mTextSelectionEnd;
434         int[] mLineCharOffsets;
435         int[] mLineBaselines;
436         String mHint;
437
438         ViewNodeText() {
439         }
440
441         boolean isSimple() {
442             return mTextBackgroundColor == ViewNode.TEXT_COLOR_UNDEFINED
443                     && mTextSelectionStart == 0 && mTextSelectionEnd == 0
444                     && mLineCharOffsets == null && mLineBaselines == null && mHint == null;
445         }
446
447         ViewNodeText(Parcel in, boolean simple) {
448             mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
449             mTextSize = in.readFloat();
450             mTextStyle = in.readInt();
451             mTextColor = in.readInt();
452             if (!simple) {
453                 mTextBackgroundColor = in.readInt();
454                 mTextSelectionStart = in.readInt();
455                 mTextSelectionEnd = in.readInt();
456                 mLineCharOffsets = in.createIntArray();
457                 mLineBaselines = in.createIntArray();
458                 mHint = in.readString();
459             }
460         }
461
462         void writeToParcel(Parcel out, boolean simple, boolean writeSensitive) {
463             TextUtils.writeToParcel(writeSensitive ? mText : "", out, 0);
464             out.writeFloat(mTextSize);
465             out.writeInt(mTextStyle);
466             out.writeInt(mTextColor);
467             if (!simple) {
468                 out.writeInt(mTextBackgroundColor);
469                 out.writeInt(mTextSelectionStart);
470                 out.writeInt(mTextSelectionEnd);
471                 out.writeIntArray(mLineCharOffsets);
472                 out.writeIntArray(mLineBaselines);
473                 out.writeString(mHint);
474             }
475         }
476     }
477
478     /**
479      * Describes a window in the assist data.
480      */
481     static public class WindowNode {
482         final int mX;
483         final int mY;
484         final int mWidth;
485         final int mHeight;
486         final CharSequence mTitle;
487         final int mDisplayId;
488         final ViewNode mRoot;
489
490         WindowNode(AssistStructure assist, ViewRootImpl root, boolean forAutoFill, int flags) {
491             View view = root.getView();
492             Rect rect = new Rect();
493             view.getBoundsOnScreen(rect);
494             mX = rect.left - view.getLeft();
495             mY = rect.top - view.getTop();
496             mWidth = rect.width();
497             mHeight = rect.height();
498             mTitle = root.getTitle();
499             mDisplayId = root.getDisplayId();
500             mRoot = new ViewNode();
501
502             ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false);
503             if ((root.getWindowFlags() & WindowManager.LayoutParams.FLAG_SECURE) != 0) {
504                 if (forAutoFill) {
505                     final int viewFlags = resolveViewAutofillFlags(view.getContext(), flags);
506                     view.onProvideAutofillStructure(builder, viewFlags);
507                 } else {
508                     // This is a secure window, so it doesn't want a screenshot, and that
509                     // means we should also not copy out its view hierarchy for Assist
510                     view.onProvideStructure(builder);
511                     builder.setAssistBlocked(true);
512                     return;
513                 }
514             }
515             if (forAutoFill) {
516                 final int viewFlags = resolveViewAutofillFlags(view.getContext(), flags);
517                 view.dispatchProvideAutofillStructure(builder, viewFlags);
518             } else {
519                 view.dispatchProvideStructure(builder);
520             }
521         }
522
523         WindowNode(ParcelTransferReader reader) {
524             Parcel in = reader.readParcel(VALIDATE_WINDOW_TOKEN, 0);
525             reader.mNumReadWindows++;
526             mX = in.readInt();
527             mY = in.readInt();
528             mWidth = in.readInt();
529             mHeight = in.readInt();
530             mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
531             mDisplayId = in.readInt();
532             mRoot = new ViewNode(reader, 0);
533         }
534
535         int resolveViewAutofillFlags(Context context, int fillRequestFlags) {
536             return (fillRequestFlags & FillRequest.FLAG_MANUAL_REQUEST) != 0
537                         || context.isAutofillCompatibilityEnabled()
538                     ? View.AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS : 0;
539         }
540
541         void writeSelfToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix) {
542             out.writeInt(mX);
543             out.writeInt(mY);
544             out.writeInt(mWidth);
545             out.writeInt(mHeight);
546             TextUtils.writeToParcel(mTitle, out, 0);
547             out.writeInt(mDisplayId);
548         }
549
550         /**
551          * Returns the left edge of the window, in pixels, relative to the left
552          * edge of the screen.
553          */
554         public int getLeft() {
555             return mX;
556         }
557
558         /**
559          * Returns the top edge of the window, in pixels, relative to the top
560          * edge of the screen.
561          */
562         public int getTop() {
563             return mY;
564         }
565
566         /**
567          * Returns the total width of the window in pixels.
568          */
569         public int getWidth() {
570             return mWidth;
571         }
572
573         /**
574          * Returns the total height of the window in pixels.
575          */
576         public int getHeight() {
577             return mHeight;
578         }
579
580         /**
581          * Returns the title associated with the window, if it has one.
582          */
583         public CharSequence getTitle() {
584             return mTitle;
585         }
586
587         /**
588          * Returns the ID of the display this window is on, for use with
589          * {@link android.hardware.display.DisplayManager#getDisplay DisplayManager.getDisplay()}.
590          */
591         public int getDisplayId() {
592             return mDisplayId;
593         }
594
595         /**
596          * Returns the {@link ViewNode} containing the root content of the window.
597          */
598         public ViewNode getRootViewNode() {
599             return mRoot;
600         }
601     }
602
603     /**
604      * Describes a single view in the assist data.
605      */
606     static public class ViewNode {
607         /**
608          * Magic value for text color that has not been defined, which is very unlikely
609          * to be confused with a real text color.
610          */
611         public static final int TEXT_COLOR_UNDEFINED = 1;
612
613         public static final int TEXT_STYLE_BOLD = 1<<0;
614         public static final int TEXT_STYLE_ITALIC = 1<<1;
615         public static final int TEXT_STYLE_UNDERLINE = 1<<2;
616         public static final int TEXT_STYLE_STRIKE_THRU = 1<<3;
617
618         int mId = View.NO_ID;
619         String mIdPackage;
620         String mIdType;
621         String mIdEntry;
622
623         // TODO: once we have more flags, it might be better to store the individual
624         // fields (viewId and childId) of the field.
625         AutofillId mAutofillId;
626         @View.AutofillType int mAutofillType = View.AUTOFILL_TYPE_NONE;
627         @Nullable String[] mAutofillHints;
628         AutofillValue mAutofillValue;
629         CharSequence[] mAutofillOptions;
630         boolean mSanitized;
631         HtmlInfo mHtmlInfo;
632         int mMinEms = -1;
633         int mMaxEms = -1;
634         int mMaxLength = -1;
635         @Nullable String mTextIdEntry;
636         @AutofillImportance int mImportantForAutofill;
637
638         // POJO used to override some autofill-related values when the node is parcelized.
639         // Not written to parcel.
640         AutofillOverlay mAutofillOverlay;
641
642         int mX;
643         int mY;
644         int mScrollX;
645         int mScrollY;
646         int mWidth;
647         int mHeight;
648         Matrix mMatrix;
649         float mElevation;
650         float mAlpha = 1.0f;
651
652         static final int FLAGS_DISABLED = 0x00000001;
653         static final int FLAGS_VISIBILITY_MASK = View.VISIBLE|View.INVISIBLE|View.GONE;
654         static final int FLAGS_FOCUSABLE = 0x00000010;
655         static final int FLAGS_FOCUSED = 0x00000020;
656         static final int FLAGS_SELECTED = 0x00000040;
657         static final int FLAGS_ASSIST_BLOCKED = 0x00000080;
658         static final int FLAGS_CHECKABLE = 0x00000100;
659         static final int FLAGS_CHECKED = 0x00000200;
660         static final int FLAGS_CLICKABLE = 0x00000400;
661         static final int FLAGS_LONG_CLICKABLE = 0x00000800;
662         static final int FLAGS_ACCESSIBILITY_FOCUSED = 0x00001000;
663         static final int FLAGS_ACTIVATED = 0x00002000;
664         static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000;
665         static final int FLAGS_OPAQUE = 0x00008000;
666
667         // TODO: autofill data is made of many fields and ideally we should verify
668         // one-by-one to optimize what's sent over, but there isn't enough flag bits for that, we'd
669         // need to create a 'flags2' or 'autoFillFlags' field and add these flags there.
670         // So, to keep thinkg simpler for now, let's just use on flag for all of them...
671         static final int FLAGS_HAS_AUTOFILL_DATA = 0x80000000;
672         static final int FLAGS_HAS_MATRIX = 0x40000000;
673         static final int FLAGS_HAS_ALPHA = 0x20000000;
674         static final int FLAGS_HAS_ELEVATION = 0x10000000;
675         static final int FLAGS_HAS_SCROLL = 0x08000000;
676         static final int FLAGS_HAS_LARGE_COORDS = 0x04000000;
677         static final int FLAGS_HAS_CONTENT_DESCRIPTION = 0x02000000;
678         static final int FLAGS_HAS_TEXT = 0x01000000;
679         static final int FLAGS_HAS_COMPLEX_TEXT = 0x00800000;
680         static final int FLAGS_HAS_EXTRAS = 0x00400000;
681         static final int FLAGS_HAS_ID = 0x00200000;
682         static final int FLAGS_HAS_CHILDREN = 0x00100000;
683         static final int FLAGS_HAS_URL = 0x00080000;
684         static final int FLAGS_HAS_INPUT_TYPE = 0x00040000;
685         static final int FLAGS_HAS_LOCALE_LIST = 0x00010000;
686         static final int FLAGS_ALL_CONTROL = 0xfff00000;
687
688         int mFlags;
689
690         String mClassName;
691         CharSequence mContentDescription;
692
693         ViewNodeText mText;
694         int mInputType;
695         String mWebScheme;
696         String mWebDomain;
697         Bundle mExtras;
698         LocaleList mLocaleList;
699
700         ViewNode[] mChildren;
701
702         ViewNode() {
703         }
704
705         ViewNode(ParcelTransferReader reader, int nestingLevel) {
706             final Parcel in = reader.readParcel(VALIDATE_VIEW_TOKEN, nestingLevel);
707             reader.mNumReadViews++;
708             final PooledStringReader preader = reader.mStringReader;
709             mClassName = preader.readString();
710             mFlags = in.readInt();
711             final int flags = mFlags;
712             if ((flags&FLAGS_HAS_ID) != 0) {
713                 mId = in.readInt();
714                 if (mId != View.NO_ID) {
715                     mIdEntry = preader.readString();
716                     if (mIdEntry != null) {
717                         mIdType = preader.readString();
718                         mIdPackage = preader.readString();
719                     }
720                 }
721             }
722
723             if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0) {
724                 mSanitized = in.readInt() == 1;
725                 mAutofillId = in.readParcelable(null);
726                 mAutofillType = in.readInt();
727                 mAutofillHints = in.readStringArray();
728                 mAutofillValue = in.readParcelable(null);
729                 mAutofillOptions = in.readCharSequenceArray();
730                 final Parcelable p = in.readParcelable(null);
731                 if (p instanceof HtmlInfo) {
732                     mHtmlInfo = (HtmlInfo) p;
733                 }
734                 mMinEms = in.readInt();
735                 mMaxEms = in.readInt();
736                 mMaxLength = in.readInt();
737                 mTextIdEntry = preader.readString();
738                 mImportantForAutofill = in.readInt();
739             }
740             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
741                 mX = in.readInt();
742                 mY = in.readInt();
743                 mWidth = in.readInt();
744                 mHeight = in.readInt();
745             } else {
746                 int val = in.readInt();
747                 mX = val&0x7fff;
748                 mY = (val>>16)&0x7fff;
749                 val = in.readInt();
750                 mWidth = val&0x7fff;
751                 mHeight = (val>>16)&0x7fff;
752             }
753             if ((flags&FLAGS_HAS_SCROLL) != 0) {
754                 mScrollX = in.readInt();
755                 mScrollY = in.readInt();
756             }
757             if ((flags&FLAGS_HAS_MATRIX) != 0) {
758                 mMatrix = new Matrix();
759                 in.readFloatArray(reader.mTmpMatrix);
760                 mMatrix.setValues(reader.mTmpMatrix);
761             }
762             if ((flags&FLAGS_HAS_ELEVATION) != 0) {
763                 mElevation = in.readFloat();
764             }
765             if ((flags&FLAGS_HAS_ALPHA) != 0) {
766                 mAlpha = in.readFloat();
767             }
768             if ((flags&FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
769                 mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
770             }
771             if ((flags&FLAGS_HAS_TEXT) != 0) {
772                 mText = new ViewNodeText(in, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0);
773             }
774             if ((flags&FLAGS_HAS_INPUT_TYPE) != 0) {
775                 mInputType = in.readInt();
776             }
777             if ((flags&FLAGS_HAS_URL) != 0) {
778                 mWebScheme = in.readString();
779                 mWebDomain = in.readString();
780             }
781             if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
782                 mLocaleList = in.readParcelable(null);
783             }
784             if ((flags&FLAGS_HAS_EXTRAS) != 0) {
785                 mExtras = in.readBundle();
786             }
787             if ((flags&FLAGS_HAS_CHILDREN) != 0) {
788                 final int NCHILDREN = in.readInt();
789                 if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG,
790                         "Preparing to read " + NCHILDREN
791                                 + " children: @ #" + reader.mNumReadViews
792                                 + ", level " + nestingLevel);
793                 mChildren = new ViewNode[NCHILDREN];
794                 for (int i=0; i<NCHILDREN; i++) {
795                     mChildren[i] = new ViewNode(reader, nestingLevel + 1);
796                 }
797             }
798         }
799
800         int writeSelfToParcel(Parcel out, PooledStringWriter pwriter, boolean sanitizeOnWrite,
801                 float[] tmpMatrix) {
802             // Guard used to skip non-sanitized data when writing for autofill.
803             boolean writeSensitive = true;
804
805             int flags = mFlags & ~FLAGS_ALL_CONTROL;
806
807             if (mId != View.NO_ID) {
808                 flags |= FLAGS_HAS_ID;
809             }
810             if (mAutofillId != null) {
811                 flags |= FLAGS_HAS_AUTOFILL_DATA;
812             }
813             if ((mX&~0x7fff) != 0 || (mY&~0x7fff) != 0
814                     || (mWidth&~0x7fff) != 0 | (mHeight&~0x7fff) != 0) {
815                 flags |= FLAGS_HAS_LARGE_COORDS;
816             }
817             if (mScrollX != 0 || mScrollY != 0) {
818                 flags |= FLAGS_HAS_SCROLL;
819             }
820             if (mMatrix != null) {
821                 flags |= FLAGS_HAS_MATRIX;
822             }
823             if (mElevation != 0) {
824                 flags |= FLAGS_HAS_ELEVATION;
825             }
826             if (mAlpha != 1.0f) {
827                 flags |= FLAGS_HAS_ALPHA;
828             }
829             if (mContentDescription != null) {
830                 flags |= FLAGS_HAS_CONTENT_DESCRIPTION;
831             }
832             if (mText != null) {
833                 flags |= FLAGS_HAS_TEXT;
834                 if (!mText.isSimple()) {
835                     flags |= FLAGS_HAS_COMPLEX_TEXT;
836                 }
837             }
838             if (mInputType != 0) {
839                 flags |= FLAGS_HAS_INPUT_TYPE;
840             }
841             if (mWebScheme != null || mWebDomain != null) {
842                 flags |= FLAGS_HAS_URL;
843             }
844             if (mLocaleList != null) {
845                 flags |= FLAGS_HAS_LOCALE_LIST;
846             }
847             if (mExtras != null) {
848                 flags |= FLAGS_HAS_EXTRAS;
849             }
850             if (mChildren != null) {
851                 flags |= FLAGS_HAS_CHILDREN;
852             }
853
854             pwriter.writeString(mClassName);
855
856             int writtenFlags = flags;
857             if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0 && (mSanitized || !sanitizeOnWrite)) {
858                 // Remove 'checked' from sanitized autofill request.
859                 writtenFlags = flags & ~FLAGS_CHECKED;
860             }
861             if (mAutofillOverlay != null) {
862                 if (mAutofillOverlay.focused) {
863                     writtenFlags |= ViewNode.FLAGS_FOCUSED;
864                 } else {
865                     writtenFlags &= ~ViewNode.FLAGS_FOCUSED;
866                 }
867             }
868
869             out.writeInt(writtenFlags);
870             if ((flags&FLAGS_HAS_ID) != 0) {
871                 out.writeInt(mId);
872                 if (mId != View.NO_ID) {
873                     pwriter.writeString(mIdEntry);
874                     if (mIdEntry != null) {
875                         pwriter.writeString(mIdType);
876                         pwriter.writeString(mIdPackage);
877                     }
878                 }
879             }
880
881             if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0) {
882                 writeSensitive = mSanitized || !sanitizeOnWrite;
883                 out.writeInt(mSanitized ? 1 : 0);
884                 out.writeParcelable(mAutofillId, 0);
885                 out.writeInt(mAutofillType);
886                 out.writeStringArray(mAutofillHints);
887                 final AutofillValue sanitizedValue;
888                 if (writeSensitive) {
889                     sanitizedValue = mAutofillValue;
890                 } else if (mAutofillOverlay != null && mAutofillOverlay.value != null) {
891                     sanitizedValue = mAutofillOverlay.value;
892                 } else {
893                     sanitizedValue = null;
894                 }
895                 out.writeParcelable(sanitizedValue,  0);
896                 out.writeCharSequenceArray(mAutofillOptions);
897                 if (mHtmlInfo instanceof Parcelable) {
898                     out.writeParcelable((Parcelable) mHtmlInfo, 0);
899                 } else {
900                     out.writeParcelable(null, 0);
901                 }
902                 out.writeInt(mMinEms);
903                 out.writeInt(mMaxEms);
904                 out.writeInt(mMaxLength);
905                 pwriter.writeString(mTextIdEntry);
906                 out.writeInt(mImportantForAutofill);
907             }
908             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
909                 out.writeInt(mX);
910                 out.writeInt(mY);
911                 out.writeInt(mWidth);
912                 out.writeInt(mHeight);
913             } else {
914                 out.writeInt((mY<<16) | mX);
915                 out.writeInt((mHeight<<16) | mWidth);
916             }
917             if ((flags&FLAGS_HAS_SCROLL) != 0) {
918                 out.writeInt(mScrollX);
919                 out.writeInt(mScrollY);
920             }
921             if ((flags&FLAGS_HAS_MATRIX) != 0) {
922                 mMatrix.getValues(tmpMatrix);
923                 out.writeFloatArray(tmpMatrix);
924             }
925             if ((flags&FLAGS_HAS_ELEVATION) != 0) {
926                 out.writeFloat(mElevation);
927             }
928             if ((flags&FLAGS_HAS_ALPHA) != 0) {
929                 out.writeFloat(mAlpha);
930             }
931             if ((flags&FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
932                 TextUtils.writeToParcel(mContentDescription, out, 0);
933             }
934             if ((flags&FLAGS_HAS_TEXT) != 0) {
935                 mText.writeToParcel(out, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0, writeSensitive);
936             }
937             if ((flags&FLAGS_HAS_INPUT_TYPE) != 0) {
938                 out.writeInt(mInputType);
939             }
940             if ((flags&FLAGS_HAS_URL) != 0) {
941                 out.writeString(mWebScheme);
942                 out.writeString(mWebDomain);
943             }
944             if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
945                 out.writeParcelable(mLocaleList, 0);
946             }
947             if ((flags&FLAGS_HAS_EXTRAS) != 0) {
948                 out.writeBundle(mExtras);
949             }
950             return flags;
951         }
952
953         /**
954          * Returns the ID associated with this view, as per {@link View#getId() View.getId()}.
955          */
956         public int getId() {
957             return mId;
958         }
959
960         /**
961          * If {@link #getId()} is a resource identifier, this is the package name of that
962          * identifier.  See {@link android.view.ViewStructure#setId ViewStructure.setId}
963          * for more information.
964          */
965         public String getIdPackage() {
966             return mIdPackage;
967         }
968
969         /**
970          * If {@link #getId()} is a resource identifier, this is the type name of that
971          * identifier.  See {@link android.view.ViewStructure#setId ViewStructure.setId}
972          * for more information.
973          */
974         public String getIdType() {
975             return mIdType;
976         }
977
978         /**
979          * If {@link #getId()} is a resource identifier, this is the entry name of that
980          * identifier.  See {@link android.view.ViewStructure#setId ViewStructure.setId}
981          * for more information.
982          */
983         public String getIdEntry() {
984             return mIdEntry;
985         }
986
987         /**
988          * Gets the id that can be used to autofill the view contents.
989          *
990          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes.
991          *
992          * @return id that can be used to autofill the view contents, or {@code null} if the
993          * structure was created for assist purposes.
994          */
995         @Nullable public AutofillId getAutofillId() {
996             return mAutofillId;
997         }
998
999         /**
1000          * Gets the the type of value that can be used to autofill the view contents.
1001          *
1002          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes.
1003          *
1004          * @return autofill type as defined by {@link View#getAutofillType()},
1005          * or {@link View#AUTOFILL_TYPE_NONE} if the structure was created for assist purposes.
1006          */
1007         public @View.AutofillType int getAutofillType() {
1008             return mAutofillType;
1009         }
1010
1011         /**
1012          * Describes the content of a view so that a autofill service can fill in the appropriate
1013          * data.
1014          *
1015          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1016          * not for Assist - see {@link View#getAutofillHints()} for more info.
1017          *
1018          * @return The autofill hints for this view, or {@code null} if the structure was created
1019          * for assist purposes.
1020          */
1021         @Nullable public String[] getAutofillHints() {
1022             return mAutofillHints;
1023         }
1024
1025         /**
1026          * Gets the the value of this view.
1027          *
1028          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1029          * not for assist purposes.
1030          *
1031          * @return the autofill value of this view, or {@code null} if the structure was created
1032          * for assist purposes.
1033          */
1034         @Nullable public AutofillValue getAutofillValue() {
1035             return mAutofillValue;
1036         }
1037
1038         /** @hide **/
1039         public void setAutofillOverlay(AutofillOverlay overlay) {
1040             mAutofillOverlay = overlay;
1041         }
1042
1043         /**
1044          * Gets the options that can be used to autofill this view.
1045          *
1046          * <p>Typically used by nodes whose {@link View#getAutofillType()} is a list to indicate
1047          * the meaning of each possible value in the list.
1048          *
1049          * <p>It's relevant when the {@link AssistStructure} is used for autofill purposes, not
1050          * for assist purposes.
1051          *
1052          * @return the options that can be used to autofill this view, or {@code null} if the
1053          * structure was created for assist purposes.
1054          */
1055         @Nullable public CharSequence[] getAutofillOptions() {
1056             return mAutofillOptions;
1057         }
1058
1059         /**
1060          * Gets the {@link android.text.InputType} bits of this structure.
1061          *
1062          * @return bits as defined by {@link android.text.InputType}.
1063          */
1064         public int getInputType() {
1065             return mInputType;
1066         }
1067
1068         /** @hide */
1069         public boolean isSanitized() {
1070             return mSanitized;
1071         }
1072
1073         /**
1074          * Updates the {@link AutofillValue} of this structure.
1075          *
1076          * <p>Should be used just before sending the structure to the
1077          * {@link android.service.autofill.AutofillService} for saving, since it will override the
1078          * initial value.
1079          *
1080          * @hide
1081          */
1082         public void updateAutofillValue(AutofillValue value) {
1083             mAutofillValue = value;
1084             if (value.isText()) {
1085                 if (mText == null) {
1086                     mText = new ViewNodeText();
1087                 }
1088                 mText.mText = value.getTextValue();
1089             }
1090         }
1091
1092         /**
1093          * Returns the left edge of this view, in pixels, relative to the left edge of its parent.
1094          */
1095         public int getLeft() {
1096             return mX;
1097         }
1098
1099         /**
1100          * Returns the top edge of this view, in pixels, relative to the top edge of its parent.
1101          */
1102         public int getTop() {
1103             return mY;
1104         }
1105
1106         /**
1107          * Returns the current X scroll offset of this view, as per
1108          * {@link android.view.View#getScrollX() View.getScrollX()}.
1109          */
1110         public int getScrollX() {
1111             return mScrollX;
1112         }
1113
1114         /**
1115          * Returns the current Y scroll offset of this view, as per
1116          * {@link android.view.View#getScrollX() View.getScrollY()}.
1117          */
1118         public int getScrollY() {
1119             return mScrollY;
1120         }
1121
1122         /**
1123          * Returns the width of this view, in pixels.
1124          */
1125         public int getWidth() {
1126             return mWidth;
1127         }
1128
1129         /**
1130          * Returns the height of this view, in pixels.
1131          */
1132         public int getHeight() {
1133             return mHeight;
1134         }
1135
1136         /**
1137          * Returns the transformation that has been applied to this view, such as a translation
1138          * or scaling.  The returned Matrix object is owned by ViewNode; do not modify it.
1139          * Returns null if there is no transformation applied to the view.
1140          *
1141          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1142          * not for autofill purposes.
1143          */
1144         public Matrix getTransformation() {
1145             return mMatrix;
1146         }
1147
1148         /**
1149          * Returns the visual elevation of the view, used for shadowing and other visual
1150          * characterstics, as set by {@link ViewStructure#setElevation
1151          * ViewStructure.setElevation(float)}.
1152          *
1153          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1154          * not for autofill purposes.
1155          */
1156         public float getElevation() {
1157             return mElevation;
1158         }
1159
1160         /**
1161          * Returns the alpha transformation of the view, used to reduce the overall opacity
1162          * of the view's contents, as set by {@link ViewStructure#setAlpha
1163          * ViewStructure.setAlpha(float)}.
1164          *
1165          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1166          * not for autofill purposes.
1167          */
1168         public float getAlpha() {
1169             return mAlpha;
1170         }
1171
1172         /**
1173          * Returns the visibility mode of this view, as per
1174          * {@link android.view.View#getVisibility() View.getVisibility()}.
1175          */
1176         public int getVisibility() {
1177             return mFlags&ViewNode.FLAGS_VISIBILITY_MASK;
1178         }
1179
1180         /**
1181          * Returns true if assist data has been blocked starting at this node in the hierarchy.
1182          */
1183         public boolean isAssistBlocked() {
1184             return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) != 0;
1185         }
1186
1187         /**
1188          * Returns true if this node is in an enabled state.
1189          */
1190         public boolean isEnabled() {
1191             return (mFlags&ViewNode.FLAGS_DISABLED) == 0;
1192         }
1193
1194         /**
1195          * Returns true if this node is clickable by the user.
1196          */
1197         public boolean isClickable() {
1198             return (mFlags&ViewNode.FLAGS_CLICKABLE) != 0;
1199         }
1200
1201         /**
1202          * Returns true if this node can take input focus.
1203          */
1204         public boolean isFocusable() {
1205             return (mFlags&ViewNode.FLAGS_FOCUSABLE) != 0;
1206         }
1207
1208         /**
1209          * Returns true if this node currently had input focus at the time that the
1210          * structure was collected.
1211          */
1212         public boolean isFocused() {
1213             return (mFlags&ViewNode.FLAGS_FOCUSED) != 0;
1214         }
1215
1216         /**
1217          * Returns true if this node currently had accessibility focus at the time that the
1218          * structure was collected.
1219          */
1220         public boolean isAccessibilityFocused() {
1221             return (mFlags&ViewNode.FLAGS_ACCESSIBILITY_FOCUSED) != 0;
1222         }
1223
1224         /**
1225          * Returns true if this node represents something that is checkable by the user.
1226          */
1227         public boolean isCheckable() {
1228             return (mFlags&ViewNode.FLAGS_CHECKABLE) != 0;
1229         }
1230
1231         /**
1232          * Returns true if this node is currently in a checked state.
1233          */
1234         public boolean isChecked() {
1235             return (mFlags&ViewNode.FLAGS_CHECKED) != 0;
1236         }
1237
1238         /**
1239          * Returns true if this node has currently been selected by the user.
1240          */
1241         public boolean isSelected() {
1242             return (mFlags&ViewNode.FLAGS_SELECTED) != 0;
1243         }
1244
1245         /**
1246          * Returns true if this node has currently been activated by the user.
1247          */
1248         public boolean isActivated() {
1249             return (mFlags&ViewNode.FLAGS_ACTIVATED) != 0;
1250         }
1251
1252         /**
1253          * Returns true if this node is opaque.
1254          */
1255         public boolean isOpaque() { return (mFlags&ViewNode.FLAGS_OPAQUE) != 0; }
1256
1257         /**
1258          * Returns true if this node is something the user can perform a long click/press on.
1259          */
1260         public boolean isLongClickable() {
1261             return (mFlags&ViewNode.FLAGS_LONG_CLICKABLE) != 0;
1262         }
1263
1264         /**
1265          * Returns true if this node is something the user can perform a context click on.
1266          */
1267         public boolean isContextClickable() {
1268             return (mFlags&ViewNode.FLAGS_CONTEXT_CLICKABLE) != 0;
1269         }
1270
1271         /**
1272          * Returns the class name of the node's implementation, indicating its behavior.
1273          * For example, a button will report "android.widget.Button" meaning it behaves
1274          * like a {@link android.widget.Button}.
1275          */
1276         public String getClassName() {
1277             return mClassName;
1278         }
1279
1280         /**
1281          * Returns any content description associated with the node, which semantically describes
1282          * its purpose for accessibility and other uses.
1283          */
1284         public CharSequence getContentDescription() {
1285             return mContentDescription;
1286         }
1287
1288         /**
1289          * Returns the domain of the HTML document represented by this view.
1290          *
1291          * <p>Typically used when the view associated with the view is a container for an HTML
1292          * document.
1293          *
1294          * <p><b>Warning:</b> an autofill service cannot trust the value reported by this method
1295          * without verifing its authenticity&mdash;see the "Web security" section of
1296          * {@link android.service.autofill.AutofillService} for more details.
1297          *
1298          * @return domain-only part of the document. For example, if the full URL is
1299          * {@code https://example.com/login?user=my_user}, it returns {@code example.com}.
1300          */
1301         @Nullable public String getWebDomain() {
1302             return mWebDomain;
1303         }
1304
1305         /**
1306          * @hide
1307          */
1308         public void setWebDomain(@Nullable String domain) {
1309             if (domain == null) return;
1310
1311             final Uri uri = Uri.parse(domain);
1312             if (uri == null) {
1313                 // Cannot log domain because it could contain PII;
1314                 Log.w(TAG, "Failed to parse web domain");
1315                 return;
1316             }
1317             mWebScheme = uri.getScheme();
1318             mWebDomain = uri.getHost();
1319         }
1320
1321         /**
1322          * Returns the scheme of the HTML document represented by this view.
1323          *
1324          * <p>Typically used when the view associated with the view is a container for an HTML
1325          * document.
1326          *
1327          * @return scheme-only part of the document. For example, if the full URL is
1328          * {@code https://example.com/login?user=my_user}, it returns {@code https}.
1329          */
1330         @Nullable public String getWebScheme() {
1331             return mWebScheme;
1332         }
1333
1334         /**
1335          * Returns the HTML properties associated with this view.
1336          *
1337          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1338          * not for assist purposes.
1339          *
1340          * @return the HTML properties associated with this view, or {@code null} if the
1341          * structure was created for assist purposes.
1342          */
1343         @Nullable public HtmlInfo getHtmlInfo() {
1344             return mHtmlInfo;
1345         }
1346
1347         /**
1348          * Returns the the list of locales associated with this view.
1349          */
1350         @Nullable public LocaleList getLocaleList() {
1351             return mLocaleList;
1352         }
1353
1354         /**
1355          * Returns any text associated with the node that is displayed to the user, or null
1356          * if there is none.
1357          */
1358         public CharSequence getText() {
1359             return mText != null ? mText.mText : null;
1360         }
1361
1362         /**
1363          * If {@link #getText()} is non-null, this is where the current selection starts.
1364          *
1365          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1366          * not for autofill purposes.
1367          */
1368         public int getTextSelectionStart() {
1369             return mText != null ? mText.mTextSelectionStart : -1;
1370         }
1371
1372         /**
1373          * If {@link #getText()} is non-null, this is where the current selection starts.
1374          * If there is no selection, returns the same value as {@link #getTextSelectionStart()},
1375          * indicating the cursor position.
1376          *
1377          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1378          * not for autofill purposes.
1379          */
1380         public int getTextSelectionEnd() {
1381             return mText != null ? mText.mTextSelectionEnd : -1;
1382         }
1383
1384         /**
1385          * If {@link #getText()} is non-null, this is the main text color associated with it.
1386          * If there is no text color, {@link #TEXT_COLOR_UNDEFINED} is returned.
1387          * Note that the text may also contain style spans that modify the color of specific
1388          * parts of the text.
1389          */
1390         public int getTextColor() {
1391             return mText != null ? mText.mTextColor : TEXT_COLOR_UNDEFINED;
1392         }
1393
1394         /**
1395          * If {@link #getText()} is non-null, this is the main text background color associated
1396          * with it.
1397          * If there is no text background color, {@link #TEXT_COLOR_UNDEFINED} is returned.
1398          * Note that the text may also contain style spans that modify the color of specific
1399          * parts of the text.
1400          *
1401          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1402          * not for autofill purposes.
1403          */
1404         public int getTextBackgroundColor() {
1405             return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
1406         }
1407
1408         /**
1409          * If {@link #getText()} is non-null, this is the main text size (in pixels) associated
1410          * with it.
1411          * Note that the text may also contain style spans that modify the size of specific
1412          * parts of the text.
1413          *
1414          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1415          * not for autofill purposes.
1416          */
1417         public float getTextSize() {
1418             return mText != null ? mText.mTextSize : 0;
1419         }
1420
1421         /**
1422          * If {@link #getText()} is non-null, this is the main text style associated
1423          * with it, containing a bit mask of {@link #TEXT_STYLE_BOLD},
1424          * {@link #TEXT_STYLE_BOLD}, {@link #TEXT_STYLE_STRIKE_THRU}, and/or
1425          * {@link #TEXT_STYLE_UNDERLINE}.
1426          * Note that the text may also contain style spans that modify the style of specific
1427          * parts of the text.
1428          *
1429          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1430          * not for autofill purposes.
1431          */
1432         public int getTextStyle() {
1433             return mText != null ? mText.mTextStyle : 0;
1434         }
1435
1436         /**
1437          * Return per-line offsets into the text returned by {@link #getText()}.  Each entry
1438          * in the array is a formatted line of text, and the value it contains is the offset
1439          * into the text string where that line starts.  May return null if there is no line
1440          * information.
1441          *
1442          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1443          * not for autofill purposes.
1444          */
1445         public int[] getTextLineCharOffsets() {
1446             return mText != null ? mText.mLineCharOffsets : null;
1447         }
1448
1449         /**
1450          * Return per-line baselines into the text returned by {@link #getText()}.  Each entry
1451          * in the array is a formatted line of text, and the value it contains is the baseline
1452          * where that text appears in the view.  May return null if there is no line
1453          * information.
1454          *
1455          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1456          * not for autofill purposes.
1457          */
1458         public int[] getTextLineBaselines() {
1459             return mText != null ? mText.mLineBaselines : null;
1460         }
1461
1462         /**
1463          * Gets the identifier used to set the text associated with this view.
1464          *
1465          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1466          * not for assist purposes.
1467          */
1468         @Nullable
1469         public String getTextIdEntry() {
1470             return mTextIdEntry;
1471         }
1472
1473         /**
1474          * Return additional hint text associated with the node; this is typically used with
1475          * a node that takes user input, describing to the user what the input means.
1476          */
1477         public String getHint() {
1478             return mText != null ? mText.mHint : null;
1479         }
1480
1481         /**
1482          * Return a Bundle containing optional vendor-specific extension information.
1483          */
1484         public Bundle getExtras() {
1485             return mExtras;
1486         }
1487
1488         /**
1489          * Return the number of children this node has.
1490          */
1491         public int getChildCount() {
1492             return mChildren != null ? mChildren.length : 0;
1493         }
1494
1495         /**
1496          * Return a child of this node, given an index value from 0 to
1497          * {@link #getChildCount()}-1.
1498          */
1499         public ViewNode getChildAt(int index) {
1500             return mChildren[index];
1501         }
1502
1503         /**
1504          * Returns the minimum width in ems of the text associated with this node, or {@code -1}
1505          * if not supported by the node.
1506          *
1507          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1508          * not for assist purposes.
1509          */
1510         public int getMinTextEms() {
1511             return mMinEms;
1512         }
1513
1514         /**
1515          * Returns the maximum width in ems of the text associated with this node, or {@code -1}
1516          * if not supported by the node.
1517          *
1518          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1519          * not for assist purposes.
1520          */
1521         public int getMaxTextEms() {
1522             return mMaxEms;
1523         }
1524
1525         /**
1526          * Returns the maximum length of the text associated with this node node, or {@code -1}
1527          * if not supported by the node or not set.
1528          *
1529          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1530          * not for assist purposes.
1531          */
1532         public int getMaxTextLength() {
1533             return mMaxLength;
1534         }
1535
1536         /**
1537          * Gets the {@link View#setImportantForAutofill(int) importantForAutofill mode} of
1538          * the view associated with this node.
1539          *
1540          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes.
1541          */
1542         public @AutofillImportance int getImportantForAutofill() {
1543             return mImportantForAutofill;
1544         }
1545     }
1546
1547     /**
1548      * POJO used to override some autofill-related values when the node is parcelized.
1549      *
1550      * @hide
1551      */
1552     static public class AutofillOverlay {
1553         public boolean focused;
1554         public AutofillValue value;
1555     }
1556
1557     static class ViewNodeBuilder extends ViewStructure {
1558         final AssistStructure mAssist;
1559         final ViewNode mNode;
1560         final boolean mAsync;
1561
1562         ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async) {
1563             mAssist = assist;
1564             mNode = node;
1565             mAsync = async;
1566         }
1567
1568         @Override
1569         public void setId(int id, String packageName, String typeName, String entryName) {
1570             mNode.mId = id;
1571             mNode.mIdPackage = packageName;
1572             mNode.mIdType = typeName;
1573             mNode.mIdEntry = entryName;
1574         }
1575
1576         @Override
1577         public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) {
1578             mNode.mX = left;
1579             mNode.mY = top;
1580             mNode.mScrollX = scrollX;
1581             mNode.mScrollY = scrollY;
1582             mNode.mWidth = width;
1583             mNode.mHeight = height;
1584         }
1585
1586         @Override
1587         public void setTransformation(Matrix matrix) {
1588             if (matrix == null) {
1589                 mNode.mMatrix = null;
1590             } else {
1591                 mNode.mMatrix = new Matrix(matrix);
1592             }
1593         }
1594
1595         @Override
1596         public void setElevation(float elevation) {
1597             mNode.mElevation = elevation;
1598         }
1599
1600         @Override
1601         public void setAlpha(float alpha) {
1602             mNode.mAlpha = alpha;
1603         }
1604
1605         @Override
1606         public void setVisibility(int visibility) {
1607             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_VISIBILITY_MASK) | visibility;
1608         }
1609
1610         @Override
1611         public void setAssistBlocked(boolean state) {
1612             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ASSIST_BLOCKED)
1613                     | (state ? ViewNode.FLAGS_ASSIST_BLOCKED : 0);
1614         }
1615
1616         @Override
1617         public void setEnabled(boolean state) {
1618             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_DISABLED)
1619                     | (state ? 0 : ViewNode.FLAGS_DISABLED);
1620         }
1621
1622         @Override
1623         public void setClickable(boolean state) {
1624             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CLICKABLE)
1625                     | (state ? ViewNode.FLAGS_CLICKABLE : 0);
1626         }
1627
1628         @Override
1629         public void setLongClickable(boolean state) {
1630             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_LONG_CLICKABLE)
1631                     | (state ? ViewNode.FLAGS_LONG_CLICKABLE : 0);
1632         }
1633
1634         @Override
1635         public void setContextClickable(boolean state) {
1636             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CONTEXT_CLICKABLE)
1637                     | (state ? ViewNode.FLAGS_CONTEXT_CLICKABLE : 0);
1638         }
1639
1640         @Override
1641         public void setFocusable(boolean state) {
1642             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSABLE)
1643                     | (state ? ViewNode.FLAGS_FOCUSABLE : 0);
1644         }
1645
1646         @Override
1647         public void setFocused(boolean state) {
1648             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSED)
1649                     | (state ? ViewNode.FLAGS_FOCUSED : 0);
1650         }
1651
1652         @Override
1653         public void setAccessibilityFocused(boolean state) {
1654             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACCESSIBILITY_FOCUSED)
1655                     | (state ? ViewNode.FLAGS_ACCESSIBILITY_FOCUSED : 0);
1656         }
1657
1658         @Override
1659         public void setCheckable(boolean state) {
1660             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKABLE)
1661                     | (state ? ViewNode.FLAGS_CHECKABLE : 0);
1662         }
1663
1664         @Override
1665         public void setChecked(boolean state) {
1666             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKED)
1667                     | (state ? ViewNode.FLAGS_CHECKED : 0);
1668         }
1669
1670         @Override
1671         public void setSelected(boolean state) {
1672             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_SELECTED)
1673                     | (state ? ViewNode.FLAGS_SELECTED : 0);
1674         }
1675
1676         @Override
1677         public void setActivated(boolean state) {
1678             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACTIVATED)
1679                     | (state ? ViewNode.FLAGS_ACTIVATED : 0);
1680         }
1681
1682         @Override
1683         public void setOpaque(boolean opaque) {
1684             mNode.mFlags = (mNode.mFlags & ~ViewNode.FLAGS_OPAQUE)
1685                     | (opaque ? ViewNode.FLAGS_OPAQUE : 0);
1686         }
1687
1688         @Override
1689         public void setClassName(String className) {
1690             mNode.mClassName = className;
1691         }
1692
1693         @Override
1694         public void setContentDescription(CharSequence contentDescription) {
1695             mNode.mContentDescription = contentDescription;
1696         }
1697
1698         private final ViewNodeText getNodeText() {
1699             if (mNode.mText != null) {
1700                 return mNode.mText;
1701             }
1702             mNode.mText = new ViewNodeText();
1703             return mNode.mText;
1704         }
1705
1706         @Override
1707         public void setText(CharSequence text) {
1708             ViewNodeText t = getNodeText();
1709             t.mText = TextUtils.trimNoCopySpans(text);
1710             t.mTextSelectionStart = t.mTextSelectionEnd = -1;
1711         }
1712
1713         @Override
1714         public void setText(CharSequence text, int selectionStart, int selectionEnd) {
1715             ViewNodeText t = getNodeText();
1716             t.mText = TextUtils.trimNoCopySpans(text);
1717             t.mTextSelectionStart = selectionStart;
1718             t.mTextSelectionEnd = selectionEnd;
1719         }
1720
1721         @Override
1722         public void setTextStyle(float size, int fgColor, int bgColor, int style) {
1723             ViewNodeText t = getNodeText();
1724             t.mTextColor = fgColor;
1725             t.mTextBackgroundColor = bgColor;
1726             t.mTextSize = size;
1727             t.mTextStyle = style;
1728         }
1729
1730         @Override
1731         public void setTextLines(int[] charOffsets, int[] baselines) {
1732             ViewNodeText t = getNodeText();
1733             t.mLineCharOffsets = charOffsets;
1734             t.mLineBaselines = baselines;
1735         }
1736
1737         @Override
1738         public void setTextIdEntry(@NonNull String entryName) {
1739             mNode.mTextIdEntry = Preconditions.checkNotNull(entryName);
1740         }
1741
1742         @Override
1743         public void setHint(CharSequence hint) {
1744             getNodeText().mHint = hint != null ? hint.toString() : null;
1745         }
1746
1747         @Override
1748         public CharSequence getText() {
1749             return mNode.mText != null ? mNode.mText.mText : null;
1750         }
1751
1752         @Override
1753         public int getTextSelectionStart() {
1754             return mNode.mText != null ? mNode.mText.mTextSelectionStart : -1;
1755         }
1756
1757         @Override
1758         public int getTextSelectionEnd() {
1759             return mNode.mText != null ? mNode.mText.mTextSelectionEnd : -1;
1760         }
1761
1762         @Override
1763         public CharSequence getHint() {
1764             return mNode.mText != null ? mNode.mText.mHint : null;
1765         }
1766
1767         @Override
1768         public Bundle getExtras() {
1769             if (mNode.mExtras != null) {
1770                 return mNode.mExtras;
1771             }
1772             mNode.mExtras = new Bundle();
1773             return mNode.mExtras;
1774         }
1775
1776         @Override
1777         public boolean hasExtras() {
1778             return mNode.mExtras != null;
1779         }
1780
1781         @Override
1782         public void setChildCount(int num) {
1783             mNode.mChildren = new ViewNode[num];
1784         }
1785
1786         @Override
1787         public int addChildCount(int num) {
1788             if (mNode.mChildren == null) {
1789                 setChildCount(num);
1790                 return 0;
1791             }
1792             final int start = mNode.mChildren.length;
1793             ViewNode[] newArray = new ViewNode[start + num];
1794             System.arraycopy(mNode.mChildren, 0, newArray, 0, start);
1795             mNode.mChildren = newArray;
1796             return start;
1797         }
1798
1799         @Override
1800         public int getChildCount() {
1801             return mNode.mChildren != null ? mNode.mChildren.length : 0;
1802         }
1803
1804         @Override
1805         public ViewStructure newChild(int index) {
1806             ViewNode node = new ViewNode();
1807             mNode.mChildren[index] = node;
1808             return new ViewNodeBuilder(mAssist, node, false);
1809         }
1810
1811         @Override
1812         public ViewStructure asyncNewChild(int index) {
1813             synchronized (mAssist) {
1814                 ViewNode node = new ViewNode();
1815                 mNode.mChildren[index] = node;
1816                 ViewNodeBuilder builder = new ViewNodeBuilder(mAssist, node, true);
1817                 mAssist.mPendingAsyncChildren.add(builder);
1818                 return builder;
1819             }
1820         }
1821
1822         @Override
1823         public void asyncCommit() {
1824             synchronized (mAssist) {
1825                 if (!mAsync) {
1826                     throw new IllegalStateException("Child " + this
1827                             + " was not created with ViewStructure.asyncNewChild");
1828                 }
1829                 if (!mAssist.mPendingAsyncChildren.remove(this)) {
1830                     throw new IllegalStateException("Child " + this + " already committed");
1831                 }
1832                 mAssist.notifyAll();
1833             }
1834         }
1835
1836         @Override
1837         public Rect getTempRect() {
1838             return mAssist.mTmpRect;
1839         }
1840
1841         @Override
1842         public void setAutofillId(@NonNull AutofillId id) {
1843             mNode.mAutofillId = id;
1844         }
1845
1846         @Override
1847         public void setAutofillId(@NonNull AutofillId parentId, int virtualId) {
1848             mNode.mAutofillId = new AutofillId(parentId, virtualId);
1849         }
1850
1851         @Override
1852         public AutofillId getAutofillId() {
1853             return mNode.mAutofillId;
1854         }
1855
1856         @Override
1857         public void setAutofillType(@View.AutofillType int type) {
1858             mNode.mAutofillType = type;
1859         }
1860
1861         @Override
1862         public void setAutofillHints(@Nullable String[] hints) {
1863             mNode.mAutofillHints = hints;
1864         }
1865
1866         @Override
1867         public void setAutofillValue(AutofillValue value) {
1868             mNode.mAutofillValue = value;
1869         }
1870
1871         @Override
1872         public void setAutofillOptions(CharSequence[] options) {
1873             mNode.mAutofillOptions = options;
1874         }
1875
1876         @Override
1877         public void setImportantForAutofill(@AutofillImportance int mode) {
1878             mNode.mImportantForAutofill = mode;
1879         }
1880
1881         @Override
1882         public void setInputType(int inputType) {
1883             mNode.mInputType = inputType;
1884         }
1885
1886         @Override
1887         public void setMinTextEms(int minEms) {
1888             mNode.mMinEms = minEms;
1889         }
1890
1891         @Override
1892         public void setMaxTextEms(int maxEms) {
1893             mNode.mMaxEms = maxEms;
1894         }
1895
1896         @Override
1897         public void setMaxTextLength(int maxLength) {
1898             mNode.mMaxLength = maxLength;
1899         }
1900
1901         @Override
1902         public void setDataIsSensitive(boolean sensitive) {
1903             mNode.mSanitized = !sensitive;
1904         }
1905
1906         @Override
1907         public void setWebDomain(@Nullable String domain) {
1908             mNode.setWebDomain(domain);
1909         }
1910
1911         @Override
1912         public void setLocaleList(LocaleList localeList) {
1913             mNode.mLocaleList = localeList;
1914         }
1915
1916         @Override
1917         public HtmlInfo.Builder newHtmlInfoBuilder(@NonNull String tagName) {
1918             return new HtmlInfoNodeBuilder(tagName);
1919         }
1920
1921         @Override
1922         public void setHtmlInfo(@NonNull HtmlInfo htmlInfo) {
1923             mNode.mHtmlInfo = htmlInfo;
1924         }
1925     }
1926
1927     private static final class HtmlInfoNode extends HtmlInfo implements Parcelable {
1928         private final String mTag;
1929         private final String[] mNames;
1930         private final String[] mValues;
1931
1932         // Not parcelable
1933         private ArrayList<Pair<String, String>> mAttributes;
1934
1935         private HtmlInfoNode(HtmlInfoNodeBuilder builder) {
1936             mTag = builder.mTag;
1937             if (builder.mNames == null) {
1938                 mNames = null;
1939                 mValues = null;
1940             } else {
1941                 mNames = new String[builder.mNames.size()];
1942                 mValues = new String[builder.mValues.size()];
1943                 builder.mNames.toArray(mNames);
1944                 builder.mValues.toArray(mValues);
1945             }
1946         }
1947
1948         @Override
1949         public String getTag() {
1950             return mTag;
1951         }
1952
1953         @Override
1954         public List<Pair<String, String>> getAttributes() {
1955             if (mAttributes == null && mNames != null) {
1956                 mAttributes = new ArrayList<>(mNames.length);
1957                 for (int i = 0; i < mNames.length; i++) {
1958                     final Pair<String, String> pair = new Pair<>(mNames[i], mValues[i]);
1959                     mAttributes.add(i, pair);
1960                 }
1961             }
1962             return mAttributes;
1963         }
1964
1965         @Override
1966         public int describeContents() {
1967             return 0;
1968         }
1969
1970         @Override
1971         public void writeToParcel(Parcel parcel, int flags) {
1972             parcel.writeString(mTag);
1973             parcel.writeStringArray(mNames);
1974             parcel.writeStringArray(mValues);
1975         }
1976
1977         @SuppressWarnings("hiding")
1978         public static final Creator<HtmlInfoNode> CREATOR = new Creator<HtmlInfoNode>() {
1979             @Override
1980             public HtmlInfoNode createFromParcel(Parcel parcel) {
1981                 // Always go through the builder to ensure the data ingested by
1982                 // the system obeys the contract of the builder to avoid attacks
1983                 // using specially crafted parcels.
1984                 final String tag = parcel.readString();
1985                 final HtmlInfoNodeBuilder builder = new HtmlInfoNodeBuilder(tag);
1986                 final String[] names = parcel.readStringArray();
1987                 final String[] values = parcel.readStringArray();
1988                 if (names != null && values != null) {
1989                     if (names.length != values.length) {
1990                         Log.w(TAG, "HtmlInfo attributes mismatch: names=" + names.length
1991                                 + ", values=" + values.length);
1992                     } else {
1993                         for (int i = 0; i < names.length; i++) {
1994                             builder.addAttribute(names[i], values[i]);
1995                         }
1996                     }
1997                 }
1998                 return builder.build();
1999             }
2000
2001             @Override
2002             public HtmlInfoNode[] newArray(int size) {
2003                 return new HtmlInfoNode[size];
2004             }
2005         };
2006     }
2007
2008     private static final class HtmlInfoNodeBuilder extends HtmlInfo.Builder {
2009         private final String mTag;
2010         private ArrayList<String> mNames;
2011         private ArrayList<String> mValues;
2012
2013         HtmlInfoNodeBuilder(String tag) {
2014             mTag = tag;
2015         }
2016
2017         @Override
2018         public Builder addAttribute(String name, String value) {
2019             if (mNames == null) {
2020                 mNames = new ArrayList<>();
2021                 mValues = new ArrayList<>();
2022             }
2023             mNames.add(name);
2024             mValues.add(value);
2025             return this;
2026         }
2027
2028         @Override
2029         public HtmlInfoNode build() {
2030             return new HtmlInfoNode(this);
2031         }
2032     }
2033
2034     /** @hide */
2035     public AssistStructure(Activity activity, boolean forAutoFill, int flags) {
2036         mHaveData = true;
2037         mActivityComponent = activity.getComponentName();
2038         mFlags = flags;
2039         ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews(
2040                 activity.getActivityToken());
2041         for (int i=0; i<views.size(); i++) {
2042             ViewRootImpl root = views.get(i);
2043             if (root.getView() == null) {
2044                 Log.w(TAG, "Skipping window with dettached view: " + root.getTitle());
2045                 continue;
2046             }
2047             mWindowNodes.add(new WindowNode(this, root, forAutoFill, flags));
2048         }
2049     }
2050
2051     public AssistStructure() {
2052         mHaveData = true;
2053         mActivityComponent = null;
2054         mFlags = 0;
2055     }
2056
2057     /** @hide */
2058     public AssistStructure(Parcel in) {
2059         mIsHomeActivity = in.readInt() == 1;
2060         mReceiveChannel = in.readStrongBinder();
2061     }
2062
2063     /**
2064      * Helper method used to sanitize the structure before it's written to a parcel.
2065      *
2066      * <p>Used just on autofill.
2067      * @hide
2068      */
2069     public void sanitizeForParceling(boolean sanitize) {
2070         mSanitizeOnWrite = sanitize;
2071     }
2072
2073     /** @hide */
2074     public void dump(boolean showSensitive) {
2075         if (mActivityComponent == null) {
2076             Log.i(TAG, "dump(): calling ensureData() first");
2077             ensureData();
2078         }
2079         Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString());
2080         Log.i(TAG, "Sanitize on write: " + mSanitizeOnWrite);
2081         Log.i(TAG, "Flags: " + mFlags);
2082         final int N = getWindowNodeCount();
2083         for (int i=0; i<N; i++) {
2084             WindowNode node = getWindowNodeAt(i);
2085             Log.i(TAG, "Window #" + i + " [" + node.getLeft() + "," + node.getTop()
2086                     + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getTitle());
2087             dump("  ", node.getRootViewNode(), showSensitive);
2088         }
2089     }
2090
2091     void dump(String prefix, ViewNode node, boolean showSensitive) {
2092         Log.i(TAG, prefix + "View [" + node.getLeft() + "," + node.getTop()
2093                 + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getClassName());
2094         int id = node.getId();
2095         if (id != 0) {
2096             StringBuilder sb = new StringBuilder();
2097             sb.append(prefix); sb.append("  ID: #"); sb.append(Integer.toHexString(id));
2098             String entry = node.getIdEntry();
2099             if (entry != null) {
2100                 String type = node.getIdType();
2101                 String pkg = node.getIdPackage();
2102                 sb.append(" "); sb.append(pkg); sb.append(":"); sb.append(type);
2103                 sb.append("/"); sb.append(entry);
2104             }
2105             Log.i(TAG, sb.toString());
2106         }
2107         int scrollX = node.getScrollX();
2108         int scrollY = node.getScrollY();
2109         if (scrollX != 0 || scrollY != 0) {
2110             Log.i(TAG, prefix + "  Scroll: " + scrollX + "," + scrollY);
2111         }
2112         Matrix matrix = node.getTransformation();
2113         if (matrix != null) {
2114             Log.i(TAG, prefix + "  Transformation: " + matrix);
2115         }
2116         float elevation = node.getElevation();
2117         if (elevation != 0) {
2118             Log.i(TAG, prefix + "  Elevation: " + elevation);
2119         }
2120         float alpha = node.getAlpha();
2121         if (alpha != 0) {
2122             Log.i(TAG, prefix + "  Alpha: " + elevation);
2123         }
2124         CharSequence contentDescription = node.getContentDescription();
2125         if (contentDescription != null) {
2126             Log.i(TAG, prefix + "  Content description: " + contentDescription);
2127         }
2128         CharSequence text = node.getText();
2129         if (text != null) {
2130             final String safeText = node.isSanitized() || showSensitive ? text.toString()
2131                     : "REDACTED[" + text.length() + " chars]";
2132             Log.i(TAG, prefix + "  Text (sel " + node.getTextSelectionStart() + "-"
2133                     + node.getTextSelectionEnd() + "): " + safeText);
2134             Log.i(TAG, prefix + "  Text size: " + node.getTextSize() + " , style: #"
2135                     + node.getTextStyle());
2136             Log.i(TAG, prefix + "  Text color fg: #" + Integer.toHexString(node.getTextColor())
2137                     + ", bg: #" + Integer.toHexString(node.getTextBackgroundColor()));
2138             Log.i(TAG, prefix + "  Input type: " + node.getInputType());
2139             Log.i(TAG, prefix + "  Resource id: " + node.getTextIdEntry());
2140         }
2141         String webDomain = node.getWebDomain();
2142         if (webDomain != null) {
2143             Log.i(TAG, prefix + "  Web domain: " + webDomain);
2144         }
2145         HtmlInfo htmlInfo = node.getHtmlInfo();
2146         if (htmlInfo != null) {
2147             Log.i(TAG, prefix + "  HtmlInfo: tag=" + htmlInfo.getTag()
2148                     + ", attr="+ htmlInfo.getAttributes());
2149         }
2150
2151         LocaleList localeList = node.getLocaleList();
2152         if (localeList != null) {
2153             Log.i(TAG, prefix + "  LocaleList: " + localeList);
2154         }
2155         String hint = node.getHint();
2156         if (hint != null) {
2157             Log.i(TAG, prefix + "  Hint: " + hint);
2158         }
2159         Bundle extras = node.getExtras();
2160         if (extras != null) {
2161             Log.i(TAG, prefix + "  Extras: " + extras);
2162         }
2163         if (node.isAssistBlocked()) {
2164             Log.i(TAG, prefix + "  BLOCKED");
2165         }
2166         AutofillId autofillId = node.getAutofillId();
2167         if (autofillId == null) {
2168             Log.i(TAG, prefix + " NO autofill ID");
2169         } else {
2170             Log.i(TAG, prefix + "Autofill info: id= " + autofillId
2171                     + ", type=" + node.getAutofillType()
2172                     + ", options=" + Arrays.toString(node.getAutofillOptions())
2173                     + ", hints=" + Arrays.toString(node.getAutofillHints())
2174                     + ", value=" + node.getAutofillValue()
2175                     + ", sanitized=" + node.isSanitized()
2176                     + ", importantFor=" + node.getImportantForAutofill());
2177         }
2178
2179         final int NCHILDREN = node.getChildCount();
2180         if (NCHILDREN > 0) {
2181             Log.i(TAG, prefix + "  Children:");
2182             String cprefix = prefix + "    ";
2183             for (int i=0; i<NCHILDREN; i++) {
2184                 ViewNode cnode = node.getChildAt(i);
2185                 dump(cprefix, cnode, showSensitive);
2186             }
2187         }
2188     }
2189
2190     /**
2191      * Return the activity this AssistStructure came from.
2192      */
2193     public ComponentName getActivityComponent() {
2194         ensureData();
2195         return mActivityComponent;
2196     }
2197
2198     /**
2199      * Called by Autofill server when app forged a different value.
2200      *
2201      * @hide
2202      */
2203     public void setActivityComponent(ComponentName componentName) {
2204         ensureData();
2205         mActivityComponent = componentName;
2206     }
2207
2208     /** @hide */
2209     public int getFlags() {
2210         return mFlags;
2211     }
2212
2213     /**
2214      * Returns whether the activity associated with this AssistStructure was the home activity
2215      * (Launcher) at the time the assist data was acquired.
2216      * @return Whether the activity was the home activity.
2217      * @see android.content.Intent#CATEGORY_HOME
2218      */
2219     public boolean isHomeActivity() {
2220         return mIsHomeActivity;
2221     }
2222
2223     /**
2224      * Return the number of window contents that have been collected in this assist data.
2225      */
2226     public int getWindowNodeCount() {
2227         ensureData();
2228         return mWindowNodes.size();
2229     }
2230
2231     /**
2232      * Return one of the windows in the assist data.
2233      * @param index Which window to retrieve, may be 0 to {@link #getWindowNodeCount()}-1.
2234      */
2235     public WindowNode getWindowNodeAt(int index) {
2236         ensureData();
2237         return mWindowNodes.get(index);
2238     }
2239
2240     /** @hide */
2241     public void ensureData() {
2242         if (mHaveData) {
2243             return;
2244         }
2245         mHaveData = true;
2246         ParcelTransferReader reader = new ParcelTransferReader(mReceiveChannel);
2247         reader.go();
2248     }
2249
2250     boolean waitForReady() {
2251         boolean skipStructure = false;
2252         synchronized (this) {
2253             long endTime = SystemClock.uptimeMillis() + 5000;
2254             long now;
2255             while (mPendingAsyncChildren.size() > 0 && (now=SystemClock.uptimeMillis()) < endTime) {
2256                 try {
2257                     wait(endTime-now);
2258                 } catch (InterruptedException e) {
2259                 }
2260             }
2261             if (mPendingAsyncChildren.size() > 0) {
2262                 // We waited too long, assume none of the assist structure is valid.
2263                 Log.w(TAG, "Skipping assist structure, waiting too long for async children (have "
2264                         + mPendingAsyncChildren.size() + " remaining");
2265                 skipStructure = true;
2266             }
2267         }
2268         return !skipStructure;
2269     }
2270
2271     /** @hide */
2272     public void clearSendChannel() {
2273         if (mSendChannel != null) {
2274             mSendChannel.mAssistStructure = null;
2275         }
2276     }
2277
2278     @Override
2279     public int describeContents() {
2280         return 0;
2281     }
2282
2283     @Override
2284     public void writeToParcel(Parcel out, int flags) {
2285         out.writeInt(mIsHomeActivity ? 1 : 0);
2286         if (mHaveData) {
2287             // This object holds its data.  We want to write a send channel that the
2288             // other side can use to retrieve that data.
2289             if (mSendChannel == null) {
2290                 mSendChannel = new SendChannel(this);
2291             }
2292             out.writeStrongBinder(mSendChannel);
2293         } else {
2294             // This object doesn't hold its data, so just propagate along its receive channel.
2295             out.writeStrongBinder(mReceiveChannel);
2296         }
2297     }
2298
2299     public static final Parcelable.Creator<AssistStructure> CREATOR
2300             = new Parcelable.Creator<AssistStructure>() {
2301         @Override
2302         public AssistStructure createFromParcel(Parcel in) {
2303             return new AssistStructure(in);
2304         }
2305
2306         @Override
2307         public AssistStructure[] newArray(int size) {
2308             return new AssistStructure[size];
2309         }
2310     };
2311 }