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