1package android.app.assist;
2
3import android.annotation.NonNull;
4import android.annotation.Nullable;
5import android.app.Activity;
6import android.content.ComponentName;
7import android.content.Context;
8import android.graphics.Matrix;
9import android.graphics.Rect;
10import android.net.Uri;
11import android.os.BadParcelableException;
12import android.os.Binder;
13import android.os.Bundle;
14import android.os.IBinder;
15import android.os.LocaleList;
16import android.os.Parcel;
17import android.os.Parcelable;
18import android.os.PooledStringReader;
19import android.os.PooledStringWriter;
20import android.os.RemoteException;
21import android.os.SystemClock;
22import android.service.autofill.FillRequest;
23import android.text.TextUtils;
24import android.util.Log;
25import android.util.Pair;
26import android.view.View;
27import android.view.View.AutofillImportance;
28import android.view.ViewRootImpl;
29import android.view.ViewStructure;
30import android.view.ViewStructure.HtmlInfo;
31import android.view.ViewStructure.HtmlInfo.Builder;
32import android.view.WindowManager;
33import android.view.WindowManagerGlobal;
34import android.view.autofill.AutofillId;
35import android.view.autofill.AutofillValue;
36
37import com.android.internal.util.Preconditions;
38
39import java.util.ArrayList;
40import java.util.Arrays;
41import 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 */
57public 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    // TODO(b/35708678): temporary method that disable one-way warning flag on binder.
2241    /** @hide */
2242    public void ensureDataForAutofill() {
2243        if (mHaveData) {
2244            return;
2245        }
2246        mHaveData = true;
2247        Binder.allowBlocking(mReceiveChannel);
2248        try {
2249            ParcelTransferReader reader = new ParcelTransferReader(mReceiveChannel);
2250            reader.go();
2251        } finally {
2252            Binder.defaultBlocking(mReceiveChannel);
2253        }
2254    }
2255
2256    /** @hide */
2257    public void ensureData() {
2258        if (mHaveData) {
2259            return;
2260        }
2261        mHaveData = true;
2262        ParcelTransferReader reader = new ParcelTransferReader(mReceiveChannel);
2263        reader.go();
2264    }
2265
2266    boolean waitForReady() {
2267        boolean skipStructure = false;
2268        synchronized (this) {
2269            long endTime = SystemClock.uptimeMillis() + 5000;
2270            long now;
2271            while (mPendingAsyncChildren.size() > 0 && (now=SystemClock.uptimeMillis()) < endTime) {
2272                try {
2273                    wait(endTime-now);
2274                } catch (InterruptedException e) {
2275                }
2276            }
2277            if (mPendingAsyncChildren.size() > 0) {
2278                // We waited too long, assume none of the assist structure is valid.
2279                Log.w(TAG, "Skipping assist structure, waiting too long for async children (have "
2280                        + mPendingAsyncChildren.size() + " remaining");
2281                skipStructure = true;
2282            }
2283        }
2284        return !skipStructure;
2285    }
2286
2287    /** @hide */
2288    public void clearSendChannel() {
2289        if (mSendChannel != null) {
2290            mSendChannel.mAssistStructure = null;
2291        }
2292    }
2293
2294    @Override
2295    public int describeContents() {
2296        return 0;
2297    }
2298
2299    @Override
2300    public void writeToParcel(Parcel out, int flags) {
2301        out.writeInt(mIsHomeActivity ? 1 : 0);
2302        if (mHaveData) {
2303            // This object holds its data.  We want to write a send channel that the
2304            // other side can use to retrieve that data.
2305            if (mSendChannel == null) {
2306                mSendChannel = new SendChannel(this);
2307            }
2308            out.writeStrongBinder(mSendChannel);
2309        } else {
2310            // This object doesn't hold its data, so just propagate along its receive channel.
2311            out.writeStrongBinder(mReceiveChannel);
2312        }
2313    }
2314
2315    public static final Parcelable.Creator<AssistStructure> CREATOR
2316            = new Parcelable.Creator<AssistStructure>() {
2317        @Override
2318        public AssistStructure createFromParcel(Parcel in) {
2319            return new AssistStructure(in);
2320        }
2321
2322        @Override
2323        public AssistStructure[] newArray(int size) {
2324            return new AssistStructure[size];
2325        }
2326    };
2327}
2328