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