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