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