1 package android.app.assist;
3 import android.annotation.NonNull;
4 import android.annotation.Nullable;
5 import android.app.Activity;
6 import android.content.ComponentName;
7 import android.content.Context;
8 import android.graphics.Matrix;
9 import android.graphics.Rect;
10 import android.net.Uri;
11 import android.os.BadParcelableException;
12 import android.os.Binder;
13 import android.os.Bundle;
14 import android.os.IBinder;
15 import android.os.LocaleList;
16 import android.os.Parcel;
17 import android.os.Parcelable;
18 import android.os.PooledStringReader;
19 import android.os.PooledStringWriter;
20 import android.os.RemoteException;
21 import android.os.SystemClock;
22 import android.service.autofill.FillRequest;
23 import android.text.TextUtils;
24 import android.util.Log;
25 import android.util.Pair;
26 import android.view.View;
27 import android.view.View.AutofillImportance;
28 import android.view.ViewRootImpl;
29 import android.view.ViewStructure;
30 import android.view.ViewStructure.HtmlInfo;
31 import android.view.ViewStructure.HtmlInfo.Builder;
32 import android.view.WindowManager;
33 import android.view.WindowManagerGlobal;
34 import android.view.autofill.AutofillId;
35 import android.view.autofill.AutofillValue;
37 import com.android.internal.util.Preconditions;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.List;
44 * Assist data automatically created by the platform's implementation of assist and autofill.
46 * <p>The structure is used for assist purposes when created by
47 * {@link android.app.Activity#onProvideAssistData}, {@link View#onProvideStructure(ViewStructure)},
48 * or {@link View#onProvideVirtualStructure(ViewStructure)}.
50 * <p>The structure is used for autofill purposes when created by
51 * {@link View#onProvideAutofillStructure(ViewStructure, int)},
52 * or {@link View#onProvideAutofillVirtualStructure(ViewStructure, int)}.
54 * <p>For performance reasons, some properties of the assist data might be available just for assist
55 * or autofill purposes; in those case, the property availability will be document in its javadoc.
57 public class AssistStructure implements Parcelable {
58 static final String TAG = "AssistStructure";
60 static final boolean DEBUG_PARCEL = false;
61 static final boolean DEBUG_PARCEL_CHILDREN = false;
62 static final boolean DEBUG_PARCEL_TREE = false;
64 static final int VALIDATE_WINDOW_TOKEN = 0x11111111;
65 static final int VALIDATE_VIEW_TOKEN = 0x22222222;
69 ComponentName mActivityComponent;
70 private boolean mIsHomeActivity;
73 final ArrayList<WindowNode> mWindowNodes = new ArrayList<>();
75 final ArrayList<ViewNodeBuilder> mPendingAsyncChildren = new ArrayList<>();
77 SendChannel mSendChannel;
78 IBinder mReceiveChannel;
80 Rect mTmpRect = new Rect();
82 boolean mSanitizeOnWrite = false;
83 private long mAcquisitionStartTime;
84 private long mAcquisitionEndTime;
86 static final int TRANSACTION_XFER = Binder.FIRST_CALL_TRANSACTION+1;
87 static final String DESCRIPTOR = "android.app.AssistStructure";
90 public void setAcquisitionStartTime(long acquisitionStartTime) {
91 mAcquisitionStartTime = acquisitionStartTime;
95 public void setAcquisitionEndTime(long acquisitionEndTime) {
96 mAcquisitionEndTime = acquisitionEndTime;
101 * Set the home activity flag.
103 public void setHomeActivity(boolean isHomeActivity) {
104 mIsHomeActivity = isHomeActivity;
108 * Returns the time when the activity started generating assist data to build the
109 * AssistStructure. The time is as specified by {@link SystemClock#uptimeMillis()}.
111 * @see #getAcquisitionEndTime()
112 * @return Returns the acquisition start time of the assist data, in milliseconds.
114 public long getAcquisitionStartTime() {
116 return mAcquisitionStartTime;
120 * Returns the time when the activity finished generating assist data to build the
121 * AssistStructure. The time is as specified by {@link SystemClock#uptimeMillis()}.
123 * @see #getAcquisitionStartTime()
124 * @return Returns the acquisition end time of the assist data, in milliseconds.
126 public long getAcquisitionEndTime() {
128 return mAcquisitionEndTime;
131 final static class SendChannel extends Binder {
132 volatile AssistStructure mAssistStructure;
134 SendChannel(AssistStructure as) {
135 mAssistStructure = as;
138 @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
139 throws RemoteException {
140 if (code == TRANSACTION_XFER) {
141 AssistStructure as = mAssistStructure;
146 data.enforceInterface(DESCRIPTOR);
147 IBinder token = data.readStrongBinder();
148 if (DEBUG_PARCEL) Log.d(TAG, "Request for data on " + as
149 + " using token " + token);
151 if (DEBUG_PARCEL) Log.d(TAG, "Resuming partial write of " + token);
152 if (token instanceof ParcelTransferWriter) {
153 ParcelTransferWriter xfer = (ParcelTransferWriter)token;
154 xfer.writeToParcel(as, reply);
157 Log.w(TAG, "Caller supplied bad token type: " + token);
158 // Don't write anything; this is the end of the data.
161 //long start = SystemClock.uptimeMillis();
162 ParcelTransferWriter xfer = new ParcelTransferWriter(as, reply);
163 xfer.writeToParcel(as, reply);
164 //Log.i(TAG, "Time to parcel: " + (SystemClock.uptimeMillis()-start) + "ms");
167 return super.onTransact(code, data, reply, flags);
172 final static class ViewStackEntry {
178 final static class ParcelTransferWriter extends Binder {
179 final boolean mWriteStructure;
182 final ArrayList<ViewStackEntry> mViewStack = new ArrayList<>();
183 ViewStackEntry mCurViewStackEntry;
184 int mCurViewStackPos;
185 int mNumWrittenWindows;
186 int mNumWrittenViews;
187 final float[] mTmpMatrix = new float[9];
188 final boolean mSanitizeOnWrite;
190 ParcelTransferWriter(AssistStructure as, Parcel out) {
191 mSanitizeOnWrite = as.mSanitizeOnWrite;
192 mWriteStructure = as.waitForReady();
193 ComponentName.writeToParcel(as.mActivityComponent, out);
194 out.writeInt(as.mFlags);
195 out.writeLong(as.mAcquisitionStartTime);
196 out.writeLong(as.mAcquisitionEndTime);
197 mNumWindows = as.mWindowNodes.size();
198 if (mWriteStructure && mNumWindows > 0) {
199 out.writeInt(mNumWindows);
205 void writeToParcel(AssistStructure as, Parcel out) {
206 int start = out.dataPosition();
207 mNumWrittenWindows = 0;
208 mNumWrittenViews = 0;
209 boolean more = writeToParcelInner(as, out);
210 Log.i(TAG, "Flattened " + (more ? "partial" : "final") + " assist data: "
211 + (out.dataPosition() - start)
212 + " bytes, containing " + mNumWrittenWindows + " windows, "
213 + mNumWrittenViews + " views");
216 boolean writeToParcelInner(AssistStructure as, Parcel out) {
217 if (mNumWindows == 0) {
220 if (DEBUG_PARCEL) Log.d(TAG, "Creating PooledStringWriter @ " + out.dataPosition());
221 PooledStringWriter pwriter = new PooledStringWriter(out);
222 while (writeNextEntryToParcel(as, out, pwriter)) {
223 // If the parcel is above the IPC limit, then we are getting too
224 // large for a single IPC so stop here and let the caller come back when it
225 // is ready for more.
226 if (out.dataSize() > IBinder.MAX_IPC_SIZE) {
227 if (DEBUG_PARCEL) Log.d(TAG, "Assist data size is " + out.dataSize()
228 + " @ pos " + out.dataPosition() + "; returning partial result");
230 out.writeStrongBinder(this);
231 if (DEBUG_PARCEL) Log.d(TAG, "Finishing PooledStringWriter @ "
232 + out.dataPosition() + ", size " + pwriter.getStringCount());
237 if (DEBUG_PARCEL) Log.d(TAG, "Finishing PooledStringWriter @ "
238 + out.dataPosition() + ", size " + pwriter.getStringCount());
244 void pushViewStackEntry(ViewNode node, int pos) {
245 ViewStackEntry entry;
246 if (pos >= mViewStack.size()) {
247 entry = new ViewStackEntry();
248 mViewStack.add(entry);
249 if (DEBUG_PARCEL_TREE) Log.d(TAG, "New stack entry at " + pos + ": " + entry);
251 entry = mViewStack.get(pos);
252 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Existing stack entry at " + pos + ": " + entry);
255 entry.numChildren = node.getChildCount();
257 mCurViewStackEntry = entry;
260 void writeView(ViewNode child, Parcel out, PooledStringWriter pwriter, int levelAdj) {
261 if (DEBUG_PARCEL) Log.d(TAG, "write view: at " + out.dataPosition()
262 + ", windows=" + mNumWrittenWindows
263 + ", views=" + mNumWrittenViews
264 + ", level=" + (mCurViewStackPos+levelAdj));
265 out.writeInt(VALIDATE_VIEW_TOKEN);
266 int flags = child.writeSelfToParcel(out, pwriter, mSanitizeOnWrite, mTmpMatrix);
268 // If the child has children, push it on the stack to write them next.
269 if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) {
270 if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG,
271 "Preparing to write " + child.mChildren.length
272 + " children: @ #" + mNumWrittenViews
273 + ", level " + (mCurViewStackPos+levelAdj));
274 out.writeInt(child.mChildren.length);
275 int pos = ++mCurViewStackPos;
276 pushViewStackEntry(child, pos);
280 boolean writeNextEntryToParcel(AssistStructure as, Parcel out, PooledStringWriter pwriter) {
281 // Write next view node if appropriate.
282 if (mCurViewStackEntry != null) {
283 if (mCurViewStackEntry.curChild < mCurViewStackEntry.numChildren) {
284 // Write the next child in the current view.
285 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Writing child #"
286 + mCurViewStackEntry.curChild + " in " + mCurViewStackEntry.node);
287 ViewNode child = mCurViewStackEntry.node.mChildren[mCurViewStackEntry.curChild];
288 mCurViewStackEntry.curChild++;
289 writeView(child, out, pwriter, 1);
293 // We are done writing children of the current view; pop off the stack.
295 int pos = --mCurViewStackPos;
296 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Done with " + mCurViewStackEntry.node
297 + "; popping up to " + pos);
299 // Reached the last view; step to next window.
300 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Done with view hierarchy!");
301 mCurViewStackEntry = null;
304 mCurViewStackEntry = mViewStack.get(pos);
305 } while (mCurViewStackEntry.curChild >= mCurViewStackEntry.numChildren);
309 // Write the next window if appropriate.
310 int pos = mCurWindow;
311 if (pos < mNumWindows) {
312 WindowNode win = as.mWindowNodes.get(pos);
314 if (DEBUG_PARCEL) Log.d(TAG, "write window #" + pos + ": at " + out.dataPosition()
315 + ", windows=" + mNumWrittenWindows
316 + ", views=" + mNumWrittenViews);
317 out.writeInt(VALIDATE_WINDOW_TOKEN);
318 win.writeSelfToParcel(out, pwriter, mTmpMatrix);
319 mNumWrittenWindows++;
320 ViewNode root = win.mRoot;
321 mCurViewStackPos = 0;
322 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Writing initial root view " + root);
323 writeView(root, out, pwriter, 0);
331 final class ParcelTransferReader {
332 final float[] mTmpMatrix = new float[9];
333 PooledStringReader mStringReader;
338 private final IBinder mChannel;
339 private IBinder mTransferToken;
340 private Parcel mCurParcel;
342 ParcelTransferReader(IBinder channel) {
348 mActivityComponent = ComponentName.readFromParcel(mCurParcel);
349 mFlags = mCurParcel.readInt();
350 mAcquisitionStartTime = mCurParcel.readLong();
351 mAcquisitionEndTime = mCurParcel.readLong();
352 final int N = mCurParcel.readInt();
354 if (DEBUG_PARCEL) Log.d(TAG, "Creating PooledStringReader @ "
355 + mCurParcel.dataPosition());
356 mStringReader = new PooledStringReader(mCurParcel);
357 if (DEBUG_PARCEL) Log.d(TAG, "PooledStringReader size = "
358 + mStringReader.getStringCount());
359 for (int i=0; i<N; i++) {
360 mWindowNodes.add(new WindowNode(this));
363 if (DEBUG_PARCEL) Log.d(TAG, "Finished reading: at " + mCurParcel.dataPosition()
364 + ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows
365 + ", views=" + mNumReadViews);
366 mCurParcel.recycle();
367 mCurParcel = null; // Parcel cannot be used after recycled.
370 Parcel readParcel(int validateToken, int level) {
371 if (DEBUG_PARCEL) Log.d(TAG, "readParcel: at " + mCurParcel.dataPosition()
372 + ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows
373 + ", views=" + mNumReadViews + ", level=" + level);
374 int token = mCurParcel.readInt();
376 if (token != validateToken) {
377 throw new BadParcelableException("Got token " + Integer.toHexString(token)
378 + ", expected token " + Integer.toHexString(validateToken));
382 // We have run out of partial data, need to read another batch.
383 mTransferToken = mCurParcel.readStrongBinder();
384 if (mTransferToken == null) {
385 throw new IllegalStateException(
386 "Reached end of partial data without transfer token");
388 if (DEBUG_PARCEL) Log.d(TAG, "Ran out of partial data at "
389 + mCurParcel.dataPosition() + ", token " + mTransferToken);
391 if (DEBUG_PARCEL) Log.d(TAG, "Creating PooledStringReader @ "
392 + mCurParcel.dataPosition());
393 mStringReader = new PooledStringReader(mCurParcel);
394 if (DEBUG_PARCEL) Log.d(TAG, "PooledStringReader size = "
395 + mStringReader.getStringCount());
396 if (DEBUG_PARCEL) Log.d(TAG, "readParcel: at " + mCurParcel.dataPosition()
397 + ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows
398 + ", views=" + mNumReadViews);
399 mCurParcel.readInt();
403 private void fetchData() {
404 Parcel data = Parcel.obtain();
406 data.writeInterfaceToken(DESCRIPTOR);
407 data.writeStrongBinder(mTransferToken);
408 if (DEBUG_PARCEL) Log.d(TAG, "Requesting data with token " + mTransferToken);
409 if (mCurParcel != null) {
410 mCurParcel.recycle();
412 mCurParcel = Parcel.obtain();
414 mChannel.transact(TRANSACTION_XFER, data, mCurParcel, 0);
415 } catch (RemoteException e) {
416 Log.w(TAG, "Failure reading AssistStructure data", e);
417 throw new IllegalStateException("Failure reading AssistStructure data: " + e);
422 mNumReadWindows = mNumReadViews = 0;
426 final static class ViewNodeText {
430 int mTextColor = ViewNode.TEXT_COLOR_UNDEFINED;
431 int mTextBackgroundColor = ViewNode.TEXT_COLOR_UNDEFINED;
432 int mTextSelectionStart;
433 int mTextSelectionEnd;
434 int[] mLineCharOffsets;
435 int[] mLineBaselines;
442 return mTextBackgroundColor == ViewNode.TEXT_COLOR_UNDEFINED
443 && mTextSelectionStart == 0 && mTextSelectionEnd == 0
444 && mLineCharOffsets == null && mLineBaselines == null && mHint == null;
447 ViewNodeText(Parcel in, boolean simple) {
448 mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
449 mTextSize = in.readFloat();
450 mTextStyle = in.readInt();
451 mTextColor = in.readInt();
453 mTextBackgroundColor = in.readInt();
454 mTextSelectionStart = in.readInt();
455 mTextSelectionEnd = in.readInt();
456 mLineCharOffsets = in.createIntArray();
457 mLineBaselines = in.createIntArray();
458 mHint = in.readString();
462 void writeToParcel(Parcel out, boolean simple, boolean writeSensitive) {
463 TextUtils.writeToParcel(writeSensitive ? mText : "", out, 0);
464 out.writeFloat(mTextSize);
465 out.writeInt(mTextStyle);
466 out.writeInt(mTextColor);
468 out.writeInt(mTextBackgroundColor);
469 out.writeInt(mTextSelectionStart);
470 out.writeInt(mTextSelectionEnd);
471 out.writeIntArray(mLineCharOffsets);
472 out.writeIntArray(mLineBaselines);
473 out.writeString(mHint);
479 * Describes a window in the assist data.
481 static public class WindowNode {
486 final CharSequence mTitle;
487 final int mDisplayId;
488 final ViewNode mRoot;
490 WindowNode(AssistStructure assist, ViewRootImpl root, boolean forAutoFill, int flags) {
491 View view = root.getView();
492 Rect rect = new Rect();
493 view.getBoundsOnScreen(rect);
494 mX = rect.left - view.getLeft();
495 mY = rect.top - view.getTop();
496 mWidth = rect.width();
497 mHeight = rect.height();
498 mTitle = root.getTitle();
499 mDisplayId = root.getDisplayId();
500 mRoot = new ViewNode();
502 ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false);
503 if ((root.getWindowFlags() & WindowManager.LayoutParams.FLAG_SECURE) != 0) {
505 final int viewFlags = resolveViewAutofillFlags(view.getContext(), flags);
506 view.onProvideAutofillStructure(builder, viewFlags);
508 // This is a secure window, so it doesn't want a screenshot, and that
509 // means we should also not copy out its view hierarchy for Assist
510 view.onProvideStructure(builder);
511 builder.setAssistBlocked(true);
516 final int viewFlags = resolveViewAutofillFlags(view.getContext(), flags);
517 view.dispatchProvideAutofillStructure(builder, viewFlags);
519 view.dispatchProvideStructure(builder);
523 WindowNode(ParcelTransferReader reader) {
524 Parcel in = reader.readParcel(VALIDATE_WINDOW_TOKEN, 0);
525 reader.mNumReadWindows++;
528 mWidth = in.readInt();
529 mHeight = in.readInt();
530 mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
531 mDisplayId = in.readInt();
532 mRoot = new ViewNode(reader, 0);
535 int resolveViewAutofillFlags(Context context, int fillRequestFlags) {
536 return (fillRequestFlags & FillRequest.FLAG_MANUAL_REQUEST) != 0
537 || context.isAutofillCompatibilityEnabled()
538 ? View.AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS : 0;
541 void writeSelfToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix) {
544 out.writeInt(mWidth);
545 out.writeInt(mHeight);
546 TextUtils.writeToParcel(mTitle, out, 0);
547 out.writeInt(mDisplayId);
551 * Returns the left edge of the window, in pixels, relative to the left
552 * edge of the screen.
554 public int getLeft() {
559 * Returns the top edge of the window, in pixels, relative to the top
560 * edge of the screen.
562 public int getTop() {
567 * Returns the total width of the window in pixels.
569 public int getWidth() {
574 * Returns the total height of the window in pixels.
576 public int getHeight() {
581 * Returns the title associated with the window, if it has one.
583 public CharSequence getTitle() {
588 * Returns the ID of the display this window is on, for use with
589 * {@link android.hardware.display.DisplayManager#getDisplay DisplayManager.getDisplay()}.
591 public int getDisplayId() {
596 * Returns the {@link ViewNode} containing the root content of the window.
598 public ViewNode getRootViewNode() {
604 * Describes a single view in the assist data.
606 static public class ViewNode {
608 * Magic value for text color that has not been defined, which is very unlikely
609 * to be confused with a real text color.
611 public static final int TEXT_COLOR_UNDEFINED = 1;
613 public static final int TEXT_STYLE_BOLD = 1<<0;
614 public static final int TEXT_STYLE_ITALIC = 1<<1;
615 public static final int TEXT_STYLE_UNDERLINE = 1<<2;
616 public static final int TEXT_STYLE_STRIKE_THRU = 1<<3;
618 int mId = View.NO_ID;
623 // TODO: once we have more flags, it might be better to store the individual
624 // fields (viewId and childId) of the field.
625 AutofillId mAutofillId;
626 @View.AutofillType int mAutofillType = View.AUTOFILL_TYPE_NONE;
627 @Nullable String[] mAutofillHints;
628 AutofillValue mAutofillValue;
629 CharSequence[] mAutofillOptions;
635 @Nullable String mTextIdEntry;
636 @AutofillImportance int mImportantForAutofill;
638 // POJO used to override some autofill-related values when the node is parcelized.
639 // Not written to parcel.
640 AutofillOverlay mAutofillOverlay;
652 static final int FLAGS_DISABLED = 0x00000001;
653 static final int FLAGS_VISIBILITY_MASK = View.VISIBLE|View.INVISIBLE|View.GONE;
654 static final int FLAGS_FOCUSABLE = 0x00000010;
655 static final int FLAGS_FOCUSED = 0x00000020;
656 static final int FLAGS_SELECTED = 0x00000040;
657 static final int FLAGS_ASSIST_BLOCKED = 0x00000080;
658 static final int FLAGS_CHECKABLE = 0x00000100;
659 static final int FLAGS_CHECKED = 0x00000200;
660 static final int FLAGS_CLICKABLE = 0x00000400;
661 static final int FLAGS_LONG_CLICKABLE = 0x00000800;
662 static final int FLAGS_ACCESSIBILITY_FOCUSED = 0x00001000;
663 static final int FLAGS_ACTIVATED = 0x00002000;
664 static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000;
665 static final int FLAGS_OPAQUE = 0x00008000;
667 // TODO: autofill data is made of many fields and ideally we should verify
668 // one-by-one to optimize what's sent over, but there isn't enough flag bits for that, we'd
669 // need to create a 'flags2' or 'autoFillFlags' field and add these flags there.
670 // So, to keep thinkg simpler for now, let's just use on flag for all of them...
671 static final int FLAGS_HAS_AUTOFILL_DATA = 0x80000000;
672 static final int FLAGS_HAS_MATRIX = 0x40000000;
673 static final int FLAGS_HAS_ALPHA = 0x20000000;
674 static final int FLAGS_HAS_ELEVATION = 0x10000000;
675 static final int FLAGS_HAS_SCROLL = 0x08000000;
676 static final int FLAGS_HAS_LARGE_COORDS = 0x04000000;
677 static final int FLAGS_HAS_CONTENT_DESCRIPTION = 0x02000000;
678 static final int FLAGS_HAS_TEXT = 0x01000000;
679 static final int FLAGS_HAS_COMPLEX_TEXT = 0x00800000;
680 static final int FLAGS_HAS_EXTRAS = 0x00400000;
681 static final int FLAGS_HAS_ID = 0x00200000;
682 static final int FLAGS_HAS_CHILDREN = 0x00100000;
683 static final int FLAGS_HAS_URL = 0x00080000;
684 static final int FLAGS_HAS_INPUT_TYPE = 0x00040000;
685 static final int FLAGS_HAS_LOCALE_LIST = 0x00010000;
686 static final int FLAGS_ALL_CONTROL = 0xfff00000;
691 CharSequence mContentDescription;
698 LocaleList mLocaleList;
700 ViewNode[] mChildren;
705 ViewNode(ParcelTransferReader reader, int nestingLevel) {
706 final Parcel in = reader.readParcel(VALIDATE_VIEW_TOKEN, nestingLevel);
707 reader.mNumReadViews++;
708 final PooledStringReader preader = reader.mStringReader;
709 mClassName = preader.readString();
710 mFlags = in.readInt();
711 final int flags = mFlags;
712 if ((flags&FLAGS_HAS_ID) != 0) {
714 if (mId != View.NO_ID) {
715 mIdEntry = preader.readString();
716 if (mIdEntry != null) {
717 mIdType = preader.readString();
718 mIdPackage = preader.readString();
723 if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0) {
724 mSanitized = in.readInt() == 1;
725 mAutofillId = in.readParcelable(null);
726 mAutofillType = in.readInt();
727 mAutofillHints = in.readStringArray();
728 mAutofillValue = in.readParcelable(null);
729 mAutofillOptions = in.readCharSequenceArray();
730 final Parcelable p = in.readParcelable(null);
731 if (p instanceof HtmlInfo) {
732 mHtmlInfo = (HtmlInfo) p;
734 mMinEms = in.readInt();
735 mMaxEms = in.readInt();
736 mMaxLength = in.readInt();
737 mTextIdEntry = preader.readString();
738 mImportantForAutofill = in.readInt();
740 if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
743 mWidth = in.readInt();
744 mHeight = in.readInt();
746 int val = in.readInt();
748 mY = (val>>16)&0x7fff;
751 mHeight = (val>>16)&0x7fff;
753 if ((flags&FLAGS_HAS_SCROLL) != 0) {
754 mScrollX = in.readInt();
755 mScrollY = in.readInt();
757 if ((flags&FLAGS_HAS_MATRIX) != 0) {
758 mMatrix = new Matrix();
759 in.readFloatArray(reader.mTmpMatrix);
760 mMatrix.setValues(reader.mTmpMatrix);
762 if ((flags&FLAGS_HAS_ELEVATION) != 0) {
763 mElevation = in.readFloat();
765 if ((flags&FLAGS_HAS_ALPHA) != 0) {
766 mAlpha = in.readFloat();
768 if ((flags&FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
769 mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
771 if ((flags&FLAGS_HAS_TEXT) != 0) {
772 mText = new ViewNodeText(in, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0);
774 if ((flags&FLAGS_HAS_INPUT_TYPE) != 0) {
775 mInputType = in.readInt();
777 if ((flags&FLAGS_HAS_URL) != 0) {
778 mWebScheme = in.readString();
779 mWebDomain = in.readString();
781 if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
782 mLocaleList = in.readParcelable(null);
784 if ((flags&FLAGS_HAS_EXTRAS) != 0) {
785 mExtras = in.readBundle();
787 if ((flags&FLAGS_HAS_CHILDREN) != 0) {
788 final int NCHILDREN = in.readInt();
789 if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG,
790 "Preparing to read " + NCHILDREN
791 + " children: @ #" + reader.mNumReadViews
792 + ", level " + nestingLevel);
793 mChildren = new ViewNode[NCHILDREN];
794 for (int i=0; i<NCHILDREN; i++) {
795 mChildren[i] = new ViewNode(reader, nestingLevel + 1);
800 int writeSelfToParcel(Parcel out, PooledStringWriter pwriter, boolean sanitizeOnWrite,
802 // Guard used to skip non-sanitized data when writing for autofill.
803 boolean writeSensitive = true;
805 int flags = mFlags & ~FLAGS_ALL_CONTROL;
807 if (mId != View.NO_ID) {
808 flags |= FLAGS_HAS_ID;
810 if (mAutofillId != null) {
811 flags |= FLAGS_HAS_AUTOFILL_DATA;
813 if ((mX&~0x7fff) != 0 || (mY&~0x7fff) != 0
814 || (mWidth&~0x7fff) != 0 | (mHeight&~0x7fff) != 0) {
815 flags |= FLAGS_HAS_LARGE_COORDS;
817 if (mScrollX != 0 || mScrollY != 0) {
818 flags |= FLAGS_HAS_SCROLL;
820 if (mMatrix != null) {
821 flags |= FLAGS_HAS_MATRIX;
823 if (mElevation != 0) {
824 flags |= FLAGS_HAS_ELEVATION;
826 if (mAlpha != 1.0f) {
827 flags |= FLAGS_HAS_ALPHA;
829 if (mContentDescription != null) {
830 flags |= FLAGS_HAS_CONTENT_DESCRIPTION;
833 flags |= FLAGS_HAS_TEXT;
834 if (!mText.isSimple()) {
835 flags |= FLAGS_HAS_COMPLEX_TEXT;
838 if (mInputType != 0) {
839 flags |= FLAGS_HAS_INPUT_TYPE;
841 if (mWebScheme != null || mWebDomain != null) {
842 flags |= FLAGS_HAS_URL;
844 if (mLocaleList != null) {
845 flags |= FLAGS_HAS_LOCALE_LIST;
847 if (mExtras != null) {
848 flags |= FLAGS_HAS_EXTRAS;
850 if (mChildren != null) {
851 flags |= FLAGS_HAS_CHILDREN;
854 pwriter.writeString(mClassName);
856 int writtenFlags = flags;
857 if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0 && (mSanitized || !sanitizeOnWrite)) {
858 // Remove 'checked' from sanitized autofill request.
859 writtenFlags = flags & ~FLAGS_CHECKED;
861 if (mAutofillOverlay != null) {
862 if (mAutofillOverlay.focused) {
863 writtenFlags |= ViewNode.FLAGS_FOCUSED;
865 writtenFlags &= ~ViewNode.FLAGS_FOCUSED;
869 out.writeInt(writtenFlags);
870 if ((flags&FLAGS_HAS_ID) != 0) {
872 if (mId != View.NO_ID) {
873 pwriter.writeString(mIdEntry);
874 if (mIdEntry != null) {
875 pwriter.writeString(mIdType);
876 pwriter.writeString(mIdPackage);
881 if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0) {
882 writeSensitive = mSanitized || !sanitizeOnWrite;
883 out.writeInt(mSanitized ? 1 : 0);
884 out.writeParcelable(mAutofillId, 0);
885 out.writeInt(mAutofillType);
886 out.writeStringArray(mAutofillHints);
887 final AutofillValue sanitizedValue;
888 if (writeSensitive) {
889 sanitizedValue = mAutofillValue;
890 } else if (mAutofillOverlay != null && mAutofillOverlay.value != null) {
891 sanitizedValue = mAutofillOverlay.value;
893 sanitizedValue = null;
895 out.writeParcelable(sanitizedValue, 0);
896 out.writeCharSequenceArray(mAutofillOptions);
897 if (mHtmlInfo instanceof Parcelable) {
898 out.writeParcelable((Parcelable) mHtmlInfo, 0);
900 out.writeParcelable(null, 0);
902 out.writeInt(mMinEms);
903 out.writeInt(mMaxEms);
904 out.writeInt(mMaxLength);
905 pwriter.writeString(mTextIdEntry);
906 out.writeInt(mImportantForAutofill);
908 if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
911 out.writeInt(mWidth);
912 out.writeInt(mHeight);
914 out.writeInt((mY<<16) | mX);
915 out.writeInt((mHeight<<16) | mWidth);
917 if ((flags&FLAGS_HAS_SCROLL) != 0) {
918 out.writeInt(mScrollX);
919 out.writeInt(mScrollY);
921 if ((flags&FLAGS_HAS_MATRIX) != 0) {
922 mMatrix.getValues(tmpMatrix);
923 out.writeFloatArray(tmpMatrix);
925 if ((flags&FLAGS_HAS_ELEVATION) != 0) {
926 out.writeFloat(mElevation);
928 if ((flags&FLAGS_HAS_ALPHA) != 0) {
929 out.writeFloat(mAlpha);
931 if ((flags&FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
932 TextUtils.writeToParcel(mContentDescription, out, 0);
934 if ((flags&FLAGS_HAS_TEXT) != 0) {
935 mText.writeToParcel(out, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0, writeSensitive);
937 if ((flags&FLAGS_HAS_INPUT_TYPE) != 0) {
938 out.writeInt(mInputType);
940 if ((flags&FLAGS_HAS_URL) != 0) {
941 out.writeString(mWebScheme);
942 out.writeString(mWebDomain);
944 if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
945 out.writeParcelable(mLocaleList, 0);
947 if ((flags&FLAGS_HAS_EXTRAS) != 0) {
948 out.writeBundle(mExtras);
954 * Returns the ID associated with this view, as per {@link View#getId() View.getId()}.
961 * If {@link #getId()} is a resource identifier, this is the package name of that
962 * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
963 * for more information.
965 public String getIdPackage() {
970 * If {@link #getId()} is a resource identifier, this is the type name of that
971 * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
972 * for more information.
974 public String getIdType() {
979 * If {@link #getId()} is a resource identifier, this is the entry name of that
980 * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
981 * for more information.
983 public String getIdEntry() {
988 * Gets the id that can be used to autofill the view contents.
990 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes.
992 * @return id that can be used to autofill the view contents, or {@code null} if the
993 * structure was created for assist purposes.
995 @Nullable public AutofillId getAutofillId() {
1000 * Gets the the type of value that can be used to autofill the view contents.
1002 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes.
1004 * @return autofill type as defined by {@link View#getAutofillType()},
1005 * or {@link View#AUTOFILL_TYPE_NONE} if the structure was created for assist purposes.
1007 public @View.AutofillType int getAutofillType() {
1008 return mAutofillType;
1012 * Describes the content of a view so that a autofill service can fill in the appropriate
1015 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1016 * not for Assist - see {@link View#getAutofillHints()} for more info.
1018 * @return The autofill hints for this view, or {@code null} if the structure was created
1019 * for assist purposes.
1021 @Nullable public String[] getAutofillHints() {
1022 return mAutofillHints;
1026 * Gets the the value of this view.
1028 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1029 * not for assist purposes.
1031 * @return the autofill value of this view, or {@code null} if the structure was created
1032 * for assist purposes.
1034 @Nullable public AutofillValue getAutofillValue() {
1035 return mAutofillValue;
1039 public void setAutofillOverlay(AutofillOverlay overlay) {
1040 mAutofillOverlay = overlay;
1044 * Gets the options that can be used to autofill this view.
1046 * <p>Typically used by nodes whose {@link View#getAutofillType()} is a list to indicate
1047 * the meaning of each possible value in the list.
1049 * <p>It's relevant when the {@link AssistStructure} is used for autofill purposes, not
1050 * for assist purposes.
1052 * @return the options that can be used to autofill this view, or {@code null} if the
1053 * structure was created for assist purposes.
1055 @Nullable public CharSequence[] getAutofillOptions() {
1056 return mAutofillOptions;
1060 * Gets the {@link android.text.InputType} bits of this structure.
1062 * @return bits as defined by {@link android.text.InputType}.
1064 public int getInputType() {
1069 public boolean isSanitized() {
1074 * Updates the {@link AutofillValue} of this structure.
1076 * <p>Should be used just before sending the structure to the
1077 * {@link android.service.autofill.AutofillService} for saving, since it will override the
1082 public void updateAutofillValue(AutofillValue value) {
1083 mAutofillValue = value;
1084 if (value.isText()) {
1085 if (mText == null) {
1086 mText = new ViewNodeText();
1088 mText.mText = value.getTextValue();
1093 * Returns the left edge of this view, in pixels, relative to the left edge of its parent.
1095 public int getLeft() {
1100 * Returns the top edge of this view, in pixels, relative to the top edge of its parent.
1102 public int getTop() {
1107 * Returns the current X scroll offset of this view, as per
1108 * {@link android.view.View#getScrollX() View.getScrollX()}.
1110 public int getScrollX() {
1115 * Returns the current Y scroll offset of this view, as per
1116 * {@link android.view.View#getScrollX() View.getScrollY()}.
1118 public int getScrollY() {
1123 * Returns the width of this view, in pixels.
1125 public int getWidth() {
1130 * Returns the height of this view, in pixels.
1132 public int getHeight() {
1137 * Returns the transformation that has been applied to this view, such as a translation
1138 * or scaling. The returned Matrix object is owned by ViewNode; do not modify it.
1139 * Returns null if there is no transformation applied to the view.
1141 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1142 * not for autofill purposes.
1144 public Matrix getTransformation() {
1149 * Returns the visual elevation of the view, used for shadowing and other visual
1150 * characterstics, as set by {@link ViewStructure#setElevation
1151 * ViewStructure.setElevation(float)}.
1153 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1154 * not for autofill purposes.
1156 public float getElevation() {
1161 * Returns the alpha transformation of the view, used to reduce the overall opacity
1162 * of the view's contents, as set by {@link ViewStructure#setAlpha
1163 * ViewStructure.setAlpha(float)}.
1165 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1166 * not for autofill purposes.
1168 public float getAlpha() {
1173 * Returns the visibility mode of this view, as per
1174 * {@link android.view.View#getVisibility() View.getVisibility()}.
1176 public int getVisibility() {
1177 return mFlags&ViewNode.FLAGS_VISIBILITY_MASK;
1181 * Returns true if assist data has been blocked starting at this node in the hierarchy.
1183 public boolean isAssistBlocked() {
1184 return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) != 0;
1188 * Returns true if this node is in an enabled state.
1190 public boolean isEnabled() {
1191 return (mFlags&ViewNode.FLAGS_DISABLED) == 0;
1195 * Returns true if this node is clickable by the user.
1197 public boolean isClickable() {
1198 return (mFlags&ViewNode.FLAGS_CLICKABLE) != 0;
1202 * Returns true if this node can take input focus.
1204 public boolean isFocusable() {
1205 return (mFlags&ViewNode.FLAGS_FOCUSABLE) != 0;
1209 * Returns true if this node currently had input focus at the time that the
1210 * structure was collected.
1212 public boolean isFocused() {
1213 return (mFlags&ViewNode.FLAGS_FOCUSED) != 0;
1217 * Returns true if this node currently had accessibility focus at the time that the
1218 * structure was collected.
1220 public boolean isAccessibilityFocused() {
1221 return (mFlags&ViewNode.FLAGS_ACCESSIBILITY_FOCUSED) != 0;
1225 * Returns true if this node represents something that is checkable by the user.
1227 public boolean isCheckable() {
1228 return (mFlags&ViewNode.FLAGS_CHECKABLE) != 0;
1232 * Returns true if this node is currently in a checked state.
1234 public boolean isChecked() {
1235 return (mFlags&ViewNode.FLAGS_CHECKED) != 0;
1239 * Returns true if this node has currently been selected by the user.
1241 public boolean isSelected() {
1242 return (mFlags&ViewNode.FLAGS_SELECTED) != 0;
1246 * Returns true if this node has currently been activated by the user.
1248 public boolean isActivated() {
1249 return (mFlags&ViewNode.FLAGS_ACTIVATED) != 0;
1253 * Returns true if this node is opaque.
1255 public boolean isOpaque() { return (mFlags&ViewNode.FLAGS_OPAQUE) != 0; }
1258 * Returns true if this node is something the user can perform a long click/press on.
1260 public boolean isLongClickable() {
1261 return (mFlags&ViewNode.FLAGS_LONG_CLICKABLE) != 0;
1265 * Returns true if this node is something the user can perform a context click on.
1267 public boolean isContextClickable() {
1268 return (mFlags&ViewNode.FLAGS_CONTEXT_CLICKABLE) != 0;
1272 * Returns the class name of the node's implementation, indicating its behavior.
1273 * For example, a button will report "android.widget.Button" meaning it behaves
1274 * like a {@link android.widget.Button}.
1276 public String getClassName() {
1281 * Returns any content description associated with the node, which semantically describes
1282 * its purpose for accessibility and other uses.
1284 public CharSequence getContentDescription() {
1285 return mContentDescription;
1289 * Returns the domain of the HTML document represented by this view.
1291 * <p>Typically used when the view associated with the view is a container for an HTML
1294 * <p><b>Warning:</b> an autofill service cannot trust the value reported by this method
1295 * without verifing its authenticity—see the "Web security" section of
1296 * {@link android.service.autofill.AutofillService} for more details.
1298 * @return domain-only part of the document. For example, if the full URL is
1299 * {@code https://example.com/login?user=my_user}, it returns {@code example.com}.
1301 @Nullable public String getWebDomain() {
1308 public void setWebDomain(@Nullable String domain) {
1309 if (domain == null) return;
1311 final Uri uri = Uri.parse(domain);
1313 // Cannot log domain because it could contain PII;
1314 Log.w(TAG, "Failed to parse web domain");
1317 mWebScheme = uri.getScheme();
1318 mWebDomain = uri.getHost();
1322 * Returns the scheme of the HTML document represented by this view.
1324 * <p>Typically used when the view associated with the view is a container for an HTML
1327 * @return scheme-only part of the document. For example, if the full URL is
1328 * {@code https://example.com/login?user=my_user}, it returns {@code https}.
1330 @Nullable public String getWebScheme() {
1335 * Returns the HTML properties associated with this view.
1337 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1338 * not for assist purposes.
1340 * @return the HTML properties associated with this view, or {@code null} if the
1341 * structure was created for assist purposes.
1343 @Nullable public HtmlInfo getHtmlInfo() {
1348 * Returns the the list of locales associated with this view.
1350 @Nullable public LocaleList getLocaleList() {
1355 * Returns any text associated with the node that is displayed to the user, or null
1358 public CharSequence getText() {
1359 return mText != null ? mText.mText : null;
1363 * If {@link #getText()} is non-null, this is where the current selection starts.
1365 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1366 * not for autofill purposes.
1368 public int getTextSelectionStart() {
1369 return mText != null ? mText.mTextSelectionStart : -1;
1373 * If {@link #getText()} is non-null, this is where the current selection starts.
1374 * If there is no selection, returns the same value as {@link #getTextSelectionStart()},
1375 * indicating the cursor position.
1377 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1378 * not for autofill purposes.
1380 public int getTextSelectionEnd() {
1381 return mText != null ? mText.mTextSelectionEnd : -1;
1385 * If {@link #getText()} is non-null, this is the main text color associated with it.
1386 * If there is no text color, {@link #TEXT_COLOR_UNDEFINED} is returned.
1387 * Note that the text may also contain style spans that modify the color of specific
1388 * parts of the text.
1390 public int getTextColor() {
1391 return mText != null ? mText.mTextColor : TEXT_COLOR_UNDEFINED;
1395 * If {@link #getText()} is non-null, this is the main text background color associated
1397 * If there is no text background color, {@link #TEXT_COLOR_UNDEFINED} is returned.
1398 * Note that the text may also contain style spans that modify the color of specific
1399 * parts of the text.
1401 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1402 * not for autofill purposes.
1404 public int getTextBackgroundColor() {
1405 return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
1409 * If {@link #getText()} is non-null, this is the main text size (in pixels) associated
1411 * Note that the text may also contain style spans that modify the size of specific
1412 * parts of the text.
1414 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1415 * not for autofill purposes.
1417 public float getTextSize() {
1418 return mText != null ? mText.mTextSize : 0;
1422 * If {@link #getText()} is non-null, this is the main text style associated
1423 * with it, containing a bit mask of {@link #TEXT_STYLE_BOLD},
1424 * {@link #TEXT_STYLE_BOLD}, {@link #TEXT_STYLE_STRIKE_THRU}, and/or
1425 * {@link #TEXT_STYLE_UNDERLINE}.
1426 * Note that the text may also contain style spans that modify the style of specific
1427 * parts of the text.
1429 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1430 * not for autofill purposes.
1432 public int getTextStyle() {
1433 return mText != null ? mText.mTextStyle : 0;
1437 * Return per-line offsets into the text returned by {@link #getText()}. Each entry
1438 * in the array is a formatted line of text, and the value it contains is the offset
1439 * into the text string where that line starts. May return null if there is no line
1442 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1443 * not for autofill purposes.
1445 public int[] getTextLineCharOffsets() {
1446 return mText != null ? mText.mLineCharOffsets : null;
1450 * Return per-line baselines into the text returned by {@link #getText()}. Each entry
1451 * in the array is a formatted line of text, and the value it contains is the baseline
1452 * where that text appears in the view. May return null if there is no line
1455 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1456 * not for autofill purposes.
1458 public int[] getTextLineBaselines() {
1459 return mText != null ? mText.mLineBaselines : null;
1463 * Gets the identifier used to set the text associated with this view.
1465 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1466 * not for assist purposes.
1469 public String getTextIdEntry() {
1470 return mTextIdEntry;
1474 * Return additional hint text associated with the node; this is typically used with
1475 * a node that takes user input, describing to the user what the input means.
1477 public String getHint() {
1478 return mText != null ? mText.mHint : null;
1482 * Return a Bundle containing optional vendor-specific extension information.
1484 public Bundle getExtras() {
1489 * Return the number of children this node has.
1491 public int getChildCount() {
1492 return mChildren != null ? mChildren.length : 0;
1496 * Return a child of this node, given an index value from 0 to
1497 * {@link #getChildCount()}-1.
1499 public ViewNode getChildAt(int index) {
1500 return mChildren[index];
1504 * Returns the minimum width in ems of the text associated with this node, or {@code -1}
1505 * if not supported by the node.
1507 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1508 * not for assist purposes.
1510 public int getMinTextEms() {
1515 * Returns the maximum width in ems of the text associated with this node, or {@code -1}
1516 * if not supported by the node.
1518 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1519 * not for assist purposes.
1521 public int getMaxTextEms() {
1526 * Returns the maximum length of the text associated with this node node, or {@code -1}
1527 * if not supported by the node or not set.
1529 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1530 * not for assist purposes.
1532 public int getMaxTextLength() {
1537 * Gets the {@link View#setImportantForAutofill(int) importantForAutofill mode} of
1538 * the view associated with this node.
1540 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes.
1542 public @AutofillImportance int getImportantForAutofill() {
1543 return mImportantForAutofill;
1548 * POJO used to override some autofill-related values when the node is parcelized.
1552 static public class AutofillOverlay {
1553 public boolean focused;
1554 public AutofillValue value;
1557 static class ViewNodeBuilder extends ViewStructure {
1558 final AssistStructure mAssist;
1559 final ViewNode mNode;
1560 final boolean mAsync;
1562 ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async) {
1569 public void setId(int id, String packageName, String typeName, String entryName) {
1571 mNode.mIdPackage = packageName;
1572 mNode.mIdType = typeName;
1573 mNode.mIdEntry = entryName;
1577 public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) {
1580 mNode.mScrollX = scrollX;
1581 mNode.mScrollY = scrollY;
1582 mNode.mWidth = width;
1583 mNode.mHeight = height;
1587 public void setTransformation(Matrix matrix) {
1588 if (matrix == null) {
1589 mNode.mMatrix = null;
1591 mNode.mMatrix = new Matrix(matrix);
1596 public void setElevation(float elevation) {
1597 mNode.mElevation = elevation;
1601 public void setAlpha(float alpha) {
1602 mNode.mAlpha = alpha;
1606 public void setVisibility(int visibility) {
1607 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_VISIBILITY_MASK) | visibility;
1611 public void setAssistBlocked(boolean state) {
1612 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ASSIST_BLOCKED)
1613 | (state ? ViewNode.FLAGS_ASSIST_BLOCKED : 0);
1617 public void setEnabled(boolean state) {
1618 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_DISABLED)
1619 | (state ? 0 : ViewNode.FLAGS_DISABLED);
1623 public void setClickable(boolean state) {
1624 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CLICKABLE)
1625 | (state ? ViewNode.FLAGS_CLICKABLE : 0);
1629 public void setLongClickable(boolean state) {
1630 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_LONG_CLICKABLE)
1631 | (state ? ViewNode.FLAGS_LONG_CLICKABLE : 0);
1635 public void setContextClickable(boolean state) {
1636 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CONTEXT_CLICKABLE)
1637 | (state ? ViewNode.FLAGS_CONTEXT_CLICKABLE : 0);
1641 public void setFocusable(boolean state) {
1642 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSABLE)
1643 | (state ? ViewNode.FLAGS_FOCUSABLE : 0);
1647 public void setFocused(boolean state) {
1648 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSED)
1649 | (state ? ViewNode.FLAGS_FOCUSED : 0);
1653 public void setAccessibilityFocused(boolean state) {
1654 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACCESSIBILITY_FOCUSED)
1655 | (state ? ViewNode.FLAGS_ACCESSIBILITY_FOCUSED : 0);
1659 public void setCheckable(boolean state) {
1660 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKABLE)
1661 | (state ? ViewNode.FLAGS_CHECKABLE : 0);
1665 public void setChecked(boolean state) {
1666 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKED)
1667 | (state ? ViewNode.FLAGS_CHECKED : 0);
1671 public void setSelected(boolean state) {
1672 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_SELECTED)
1673 | (state ? ViewNode.FLAGS_SELECTED : 0);
1677 public void setActivated(boolean state) {
1678 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACTIVATED)
1679 | (state ? ViewNode.FLAGS_ACTIVATED : 0);
1683 public void setOpaque(boolean opaque) {
1684 mNode.mFlags = (mNode.mFlags & ~ViewNode.FLAGS_OPAQUE)
1685 | (opaque ? ViewNode.FLAGS_OPAQUE : 0);
1689 public void setClassName(String className) {
1690 mNode.mClassName = className;
1694 public void setContentDescription(CharSequence contentDescription) {
1695 mNode.mContentDescription = contentDescription;
1698 private final ViewNodeText getNodeText() {
1699 if (mNode.mText != null) {
1702 mNode.mText = new ViewNodeText();
1707 public void setText(CharSequence text) {
1708 ViewNodeText t = getNodeText();
1709 t.mText = TextUtils.trimNoCopySpans(text);
1710 t.mTextSelectionStart = t.mTextSelectionEnd = -1;
1714 public void setText(CharSequence text, int selectionStart, int selectionEnd) {
1715 ViewNodeText t = getNodeText();
1716 t.mText = TextUtils.trimNoCopySpans(text);
1717 t.mTextSelectionStart = selectionStart;
1718 t.mTextSelectionEnd = selectionEnd;
1722 public void setTextStyle(float size, int fgColor, int bgColor, int style) {
1723 ViewNodeText t = getNodeText();
1724 t.mTextColor = fgColor;
1725 t.mTextBackgroundColor = bgColor;
1727 t.mTextStyle = style;
1731 public void setTextLines(int[] charOffsets, int[] baselines) {
1732 ViewNodeText t = getNodeText();
1733 t.mLineCharOffsets = charOffsets;
1734 t.mLineBaselines = baselines;
1738 public void setTextIdEntry(@NonNull String entryName) {
1739 mNode.mTextIdEntry = Preconditions.checkNotNull(entryName);
1743 public void setHint(CharSequence hint) {
1744 getNodeText().mHint = hint != null ? hint.toString() : null;
1748 public CharSequence getText() {
1749 return mNode.mText != null ? mNode.mText.mText : null;
1753 public int getTextSelectionStart() {
1754 return mNode.mText != null ? mNode.mText.mTextSelectionStart : -1;
1758 public int getTextSelectionEnd() {
1759 return mNode.mText != null ? mNode.mText.mTextSelectionEnd : -1;
1763 public CharSequence getHint() {
1764 return mNode.mText != null ? mNode.mText.mHint : null;
1768 public Bundle getExtras() {
1769 if (mNode.mExtras != null) {
1770 return mNode.mExtras;
1772 mNode.mExtras = new Bundle();
1773 return mNode.mExtras;
1777 public boolean hasExtras() {
1778 return mNode.mExtras != null;
1782 public void setChildCount(int num) {
1783 mNode.mChildren = new ViewNode[num];
1787 public int addChildCount(int num) {
1788 if (mNode.mChildren == null) {
1792 final int start = mNode.mChildren.length;
1793 ViewNode[] newArray = new ViewNode[start + num];
1794 System.arraycopy(mNode.mChildren, 0, newArray, 0, start);
1795 mNode.mChildren = newArray;
1800 public int getChildCount() {
1801 return mNode.mChildren != null ? mNode.mChildren.length : 0;
1805 public ViewStructure newChild(int index) {
1806 ViewNode node = new ViewNode();
1807 mNode.mChildren[index] = node;
1808 return new ViewNodeBuilder(mAssist, node, false);
1812 public ViewStructure asyncNewChild(int index) {
1813 synchronized (mAssist) {
1814 ViewNode node = new ViewNode();
1815 mNode.mChildren[index] = node;
1816 ViewNodeBuilder builder = new ViewNodeBuilder(mAssist, node, true);
1817 mAssist.mPendingAsyncChildren.add(builder);
1823 public void asyncCommit() {
1824 synchronized (mAssist) {
1826 throw new IllegalStateException("Child " + this
1827 + " was not created with ViewStructure.asyncNewChild");
1829 if (!mAssist.mPendingAsyncChildren.remove(this)) {
1830 throw new IllegalStateException("Child " + this + " already committed");
1832 mAssist.notifyAll();
1837 public Rect getTempRect() {
1838 return mAssist.mTmpRect;
1842 public void setAutofillId(@NonNull AutofillId id) {
1843 mNode.mAutofillId = id;
1847 public void setAutofillId(@NonNull AutofillId parentId, int virtualId) {
1848 mNode.mAutofillId = new AutofillId(parentId, virtualId);
1852 public AutofillId getAutofillId() {
1853 return mNode.mAutofillId;
1857 public void setAutofillType(@View.AutofillType int type) {
1858 mNode.mAutofillType = type;
1862 public void setAutofillHints(@Nullable String[] hints) {
1863 mNode.mAutofillHints = hints;
1867 public void setAutofillValue(AutofillValue value) {
1868 mNode.mAutofillValue = value;
1872 public void setAutofillOptions(CharSequence[] options) {
1873 mNode.mAutofillOptions = options;
1877 public void setImportantForAutofill(@AutofillImportance int mode) {
1878 mNode.mImportantForAutofill = mode;
1882 public void setInputType(int inputType) {
1883 mNode.mInputType = inputType;
1887 public void setMinTextEms(int minEms) {
1888 mNode.mMinEms = minEms;
1892 public void setMaxTextEms(int maxEms) {
1893 mNode.mMaxEms = maxEms;
1897 public void setMaxTextLength(int maxLength) {
1898 mNode.mMaxLength = maxLength;
1902 public void setDataIsSensitive(boolean sensitive) {
1903 mNode.mSanitized = !sensitive;
1907 public void setWebDomain(@Nullable String domain) {
1908 mNode.setWebDomain(domain);
1912 public void setLocaleList(LocaleList localeList) {
1913 mNode.mLocaleList = localeList;
1917 public HtmlInfo.Builder newHtmlInfoBuilder(@NonNull String tagName) {
1918 return new HtmlInfoNodeBuilder(tagName);
1922 public void setHtmlInfo(@NonNull HtmlInfo htmlInfo) {
1923 mNode.mHtmlInfo = htmlInfo;
1927 private static final class HtmlInfoNode extends HtmlInfo implements Parcelable {
1928 private final String mTag;
1929 private final String[] mNames;
1930 private final String[] mValues;
1933 private ArrayList<Pair<String, String>> mAttributes;
1935 private HtmlInfoNode(HtmlInfoNodeBuilder builder) {
1936 mTag = builder.mTag;
1937 if (builder.mNames == null) {
1941 mNames = new String[builder.mNames.size()];
1942 mValues = new String[builder.mValues.size()];
1943 builder.mNames.toArray(mNames);
1944 builder.mValues.toArray(mValues);
1949 public String getTag() {
1954 public List<Pair<String, String>> getAttributes() {
1955 if (mAttributes == null && mNames != null) {
1956 mAttributes = new ArrayList<>(mNames.length);
1957 for (int i = 0; i < mNames.length; i++) {
1958 final Pair<String, String> pair = new Pair<>(mNames[i], mValues[i]);
1959 mAttributes.add(i, pair);
1966 public int describeContents() {
1971 public void writeToParcel(Parcel parcel, int flags) {
1972 parcel.writeString(mTag);
1973 parcel.writeStringArray(mNames);
1974 parcel.writeStringArray(mValues);
1977 @SuppressWarnings("hiding")
1978 public static final Creator<HtmlInfoNode> CREATOR = new Creator<HtmlInfoNode>() {
1980 public HtmlInfoNode createFromParcel(Parcel parcel) {
1981 // Always go through the builder to ensure the data ingested by
1982 // the system obeys the contract of the builder to avoid attacks
1983 // using specially crafted parcels.
1984 final String tag = parcel.readString();
1985 final HtmlInfoNodeBuilder builder = new HtmlInfoNodeBuilder(tag);
1986 final String[] names = parcel.readStringArray();
1987 final String[] values = parcel.readStringArray();
1988 if (names != null && values != null) {
1989 if (names.length != values.length) {
1990 Log.w(TAG, "HtmlInfo attributes mismatch: names=" + names.length
1991 + ", values=" + values.length);
1993 for (int i = 0; i < names.length; i++) {
1994 builder.addAttribute(names[i], values[i]);
1998 return builder.build();
2002 public HtmlInfoNode[] newArray(int size) {
2003 return new HtmlInfoNode[size];
2008 private static final class HtmlInfoNodeBuilder extends HtmlInfo.Builder {
2009 private final String mTag;
2010 private ArrayList<String> mNames;
2011 private ArrayList<String> mValues;
2013 HtmlInfoNodeBuilder(String tag) {
2018 public Builder addAttribute(String name, String value) {
2019 if (mNames == null) {
2020 mNames = new ArrayList<>();
2021 mValues = new ArrayList<>();
2029 public HtmlInfoNode build() {
2030 return new HtmlInfoNode(this);
2035 public AssistStructure(Activity activity, boolean forAutoFill, int flags) {
2037 mActivityComponent = activity.getComponentName();
2039 ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews(
2040 activity.getActivityToken());
2041 for (int i=0; i<views.size(); i++) {
2042 ViewRootImpl root = views.get(i);
2043 if (root.getView() == null) {
2044 Log.w(TAG, "Skipping window with dettached view: " + root.getTitle());
2047 mWindowNodes.add(new WindowNode(this, root, forAutoFill, flags));
2051 public AssistStructure() {
2053 mActivityComponent = null;
2058 public AssistStructure(Parcel in) {
2059 mIsHomeActivity = in.readInt() == 1;
2060 mReceiveChannel = in.readStrongBinder();
2064 * Helper method used to sanitize the structure before it's written to a parcel.
2066 * <p>Used just on autofill.
2069 public void sanitizeForParceling(boolean sanitize) {
2070 mSanitizeOnWrite = sanitize;
2074 public void dump(boolean showSensitive) {
2075 if (mActivityComponent == null) {
2076 Log.i(TAG, "dump(): calling ensureData() first");
2079 Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString());
2080 Log.i(TAG, "Sanitize on write: " + mSanitizeOnWrite);
2081 Log.i(TAG, "Flags: " + mFlags);
2082 final int N = getWindowNodeCount();
2083 for (int i=0; i<N; i++) {
2084 WindowNode node = getWindowNodeAt(i);
2085 Log.i(TAG, "Window #" + i + " [" + node.getLeft() + "," + node.getTop()
2086 + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getTitle());
2087 dump(" ", node.getRootViewNode(), showSensitive);
2091 void dump(String prefix, ViewNode node, boolean showSensitive) {
2092 Log.i(TAG, prefix + "View [" + node.getLeft() + "," + node.getTop()
2093 + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getClassName());
2094 int id = node.getId();
2096 StringBuilder sb = new StringBuilder();
2097 sb.append(prefix); sb.append(" ID: #"); sb.append(Integer.toHexString(id));
2098 String entry = node.getIdEntry();
2099 if (entry != null) {
2100 String type = node.getIdType();
2101 String pkg = node.getIdPackage();
2102 sb.append(" "); sb.append(pkg); sb.append(":"); sb.append(type);
2103 sb.append("/"); sb.append(entry);
2105 Log.i(TAG, sb.toString());
2107 int scrollX = node.getScrollX();
2108 int scrollY = node.getScrollY();
2109 if (scrollX != 0 || scrollY != 0) {
2110 Log.i(TAG, prefix + " Scroll: " + scrollX + "," + scrollY);
2112 Matrix matrix = node.getTransformation();
2113 if (matrix != null) {
2114 Log.i(TAG, prefix + " Transformation: " + matrix);
2116 float elevation = node.getElevation();
2117 if (elevation != 0) {
2118 Log.i(TAG, prefix + " Elevation: " + elevation);
2120 float alpha = node.getAlpha();
2122 Log.i(TAG, prefix + " Alpha: " + elevation);
2124 CharSequence contentDescription = node.getContentDescription();
2125 if (contentDescription != null) {
2126 Log.i(TAG, prefix + " Content description: " + contentDescription);
2128 CharSequence text = node.getText();
2130 final String safeText = node.isSanitized() || showSensitive ? text.toString()
2131 : "REDACTED[" + text.length() + " chars]";
2132 Log.i(TAG, prefix + " Text (sel " + node.getTextSelectionStart() + "-"
2133 + node.getTextSelectionEnd() + "): " + safeText);
2134 Log.i(TAG, prefix + " Text size: " + node.getTextSize() + " , style: #"
2135 + node.getTextStyle());
2136 Log.i(TAG, prefix + " Text color fg: #" + Integer.toHexString(node.getTextColor())
2137 + ", bg: #" + Integer.toHexString(node.getTextBackgroundColor()));
2138 Log.i(TAG, prefix + " Input type: " + node.getInputType());
2139 Log.i(TAG, prefix + " Resource id: " + node.getTextIdEntry());
2141 String webDomain = node.getWebDomain();
2142 if (webDomain != null) {
2143 Log.i(TAG, prefix + " Web domain: " + webDomain);
2145 HtmlInfo htmlInfo = node.getHtmlInfo();
2146 if (htmlInfo != null) {
2147 Log.i(TAG, prefix + " HtmlInfo: tag=" + htmlInfo.getTag()
2148 + ", attr="+ htmlInfo.getAttributes());
2151 LocaleList localeList = node.getLocaleList();
2152 if (localeList != null) {
2153 Log.i(TAG, prefix + " LocaleList: " + localeList);
2155 String hint = node.getHint();
2157 Log.i(TAG, prefix + " Hint: " + hint);
2159 Bundle extras = node.getExtras();
2160 if (extras != null) {
2161 Log.i(TAG, prefix + " Extras: " + extras);
2163 if (node.isAssistBlocked()) {
2164 Log.i(TAG, prefix + " BLOCKED");
2166 AutofillId autofillId = node.getAutofillId();
2167 if (autofillId == null) {
2168 Log.i(TAG, prefix + " NO autofill ID");
2170 Log.i(TAG, prefix + "Autofill info: id= " + autofillId
2171 + ", type=" + node.getAutofillType()
2172 + ", options=" + Arrays.toString(node.getAutofillOptions())
2173 + ", hints=" + Arrays.toString(node.getAutofillHints())
2174 + ", value=" + node.getAutofillValue()
2175 + ", sanitized=" + node.isSanitized()
2176 + ", importantFor=" + node.getImportantForAutofill());
2179 final int NCHILDREN = node.getChildCount();
2180 if (NCHILDREN > 0) {
2181 Log.i(TAG, prefix + " Children:");
2182 String cprefix = prefix + " ";
2183 for (int i=0; i<NCHILDREN; i++) {
2184 ViewNode cnode = node.getChildAt(i);
2185 dump(cprefix, cnode, showSensitive);
2191 * Return the activity this AssistStructure came from.
2193 public ComponentName getActivityComponent() {
2195 return mActivityComponent;
2199 * Called by Autofill server when app forged a different value.
2203 public void setActivityComponent(ComponentName componentName) {
2205 mActivityComponent = componentName;
2209 public int getFlags() {
2214 * Returns whether the activity associated with this AssistStructure was the home activity
2215 * (Launcher) at the time the assist data was acquired.
2216 * @return Whether the activity was the home activity.
2217 * @see android.content.Intent#CATEGORY_HOME
2219 public boolean isHomeActivity() {
2220 return mIsHomeActivity;
2224 * Return the number of window contents that have been collected in this assist data.
2226 public int getWindowNodeCount() {
2228 return mWindowNodes.size();
2232 * Return one of the windows in the assist data.
2233 * @param index Which window to retrieve, may be 0 to {@link #getWindowNodeCount()}-1.
2235 public WindowNode getWindowNodeAt(int index) {
2237 return mWindowNodes.get(index);
2241 public void ensureData() {
2246 ParcelTransferReader reader = new ParcelTransferReader(mReceiveChannel);
2250 boolean waitForReady() {
2251 boolean skipStructure = false;
2252 synchronized (this) {
2253 long endTime = SystemClock.uptimeMillis() + 5000;
2255 while (mPendingAsyncChildren.size() > 0 && (now=SystemClock.uptimeMillis()) < endTime) {
2258 } catch (InterruptedException e) {
2261 if (mPendingAsyncChildren.size() > 0) {
2262 // We waited too long, assume none of the assist structure is valid.
2263 Log.w(TAG, "Skipping assist structure, waiting too long for async children (have "
2264 + mPendingAsyncChildren.size() + " remaining");
2265 skipStructure = true;
2268 return !skipStructure;
2272 public void clearSendChannel() {
2273 if (mSendChannel != null) {
2274 mSendChannel.mAssistStructure = null;
2279 public int describeContents() {
2284 public void writeToParcel(Parcel out, int flags) {
2285 out.writeInt(mIsHomeActivity ? 1 : 0);
2287 // This object holds its data. We want to write a send channel that the
2288 // other side can use to retrieve that data.
2289 if (mSendChannel == null) {
2290 mSendChannel = new SendChannel(this);
2292 out.writeStrongBinder(mSendChannel);
2294 // This object doesn't hold its data, so just propagate along its receive channel.
2295 out.writeStrongBinder(mReceiveChannel);
2299 public static final Parcelable.Creator<AssistStructure> CREATOR
2300 = new Parcelable.Creator<AssistStructure>() {
2302 public AssistStructure createFromParcel(Parcel in) {
2303 return new AssistStructure(in);
2307 public AssistStructure[] newArray(int size) {
2308 return new AssistStructure[size];