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