Home | History | Annotate | Download | only in assist
      1 package android.app.assist;
      2 
      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;
     36 
     37 import com.android.internal.util.Preconditions;
     38 
     39 import java.util.ArrayList;
     40 import java.util.Arrays;
     41 import java.util.List;
     42 
     43 /**
     44  * Assist data automatically created by the platform's implementation of assist and autofill.
     45  *
     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)}.
     49  *
     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)}.
     53  *
     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.
     56  */
     57 public class AssistStructure implements Parcelable {
     58     static final String TAG = "AssistStructure";
     59 
     60     static final boolean DEBUG_PARCEL = false;
     61     static final boolean DEBUG_PARCEL_CHILDREN = false;
     62     static final boolean DEBUG_PARCEL_TREE = false;
     63 
     64     static final int VALIDATE_WINDOW_TOKEN = 0x11111111;
     65     static final int VALIDATE_VIEW_TOKEN = 0x22222222;
     66 
     67     boolean mHaveData;
     68 
     69     ComponentName mActivityComponent;
     70     private boolean mIsHomeActivity;
     71     private int mFlags;
     72 
     73     final ArrayList<WindowNode> mWindowNodes = new ArrayList<>();
     74 
     75     final ArrayList<ViewNodeBuilder> mPendingAsyncChildren = new ArrayList<>();
     76 
     77     SendChannel mSendChannel;
     78     IBinder mReceiveChannel;
     79 
     80     Rect mTmpRect = new Rect();
     81 
     82     boolean mSanitizeOnWrite = false;
     83     private long mAcquisitionStartTime;
     84     private long mAcquisitionEndTime;
     85 
     86     static final int TRANSACTION_XFER = Binder.FIRST_CALL_TRANSACTION+1;
     87     static final String DESCRIPTOR = "android.app.AssistStructure";
     88 
     89     /** @hide */
     90     public void setAcquisitionStartTime(long acquisitionStartTime) {
     91         mAcquisitionStartTime = acquisitionStartTime;
     92     }
     93 
     94     /** @hide */
     95     public void setAcquisitionEndTime(long acquisitionEndTime) {
     96         mAcquisitionEndTime = acquisitionEndTime;
     97     }
     98 
     99     /**
    100      * @hide
    101      * Set the home activity flag.
    102      */
    103     public void setHomeActivity(boolean isHomeActivity) {
    104         mIsHomeActivity = isHomeActivity;
    105     }
    106 
    107     /**
    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()}.
    110      *
    111      * @see #getAcquisitionEndTime()
    112      * @return Returns the acquisition start time of the assist data, in milliseconds.
    113      */
    114     public long getAcquisitionStartTime() {
    115         ensureData();
    116         return mAcquisitionStartTime;
    117     }
    118 
    119     /**
    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()}.
    122      *
    123      * @see #getAcquisitionStartTime()
    124      * @return Returns the acquisition end time of the assist data, in milliseconds.
    125      */
    126     public long getAcquisitionEndTime() {
    127         ensureData();
    128         return mAcquisitionEndTime;
    129     }
    130 
    131     final static class SendChannel extends Binder {
    132         volatile AssistStructure mAssistStructure;
    133 
    134         SendChannel(AssistStructure as) {
    135             mAssistStructure = as;
    136         }
    137 
    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;
    142                 if (as == null) {
    143                     return true;
    144                 }
    145 
    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);
    150                 if (token != null) {
    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);
    155                         return true;
    156                     }
    157                     Log.w(TAG, "Caller supplied bad token type: " + token);
    158                     // Don't write anything; this is the end of the data.
    159                     return true;
    160                 }
    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");
    165                 return true;
    166             } else {
    167                 return super.onTransact(code, data, reply, flags);
    168             }
    169         }
    170     }
    171 
    172     final static class ViewStackEntry {
    173         ViewNode node;
    174         int curChild;
    175         int numChildren;
    176     }
    177 
    178     final static class ParcelTransferWriter extends Binder {
    179         final boolean mWriteStructure;
    180         int mCurWindow;
    181         int mNumWindows;
    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;
    189 
    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);
    200             } else {
    201                 out.writeInt(0);
    202             }
    203         }
    204 
    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");
    214         }
    215 
    216         boolean writeToParcelInner(AssistStructure as, Parcel out) {
    217             if (mNumWindows == 0) {
    218                 return false;
    219             }
    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");
    229                     out.writeInt(0);
    230                     out.writeStrongBinder(this);
    231                     if (DEBUG_PARCEL) Log.d(TAG, "Finishing PooledStringWriter @ "
    232                             + out.dataPosition() + ", size " + pwriter.getStringCount());
    233                     pwriter.finish();
    234                     return true;
    235                 }
    236             }
    237             if (DEBUG_PARCEL) Log.d(TAG, "Finishing PooledStringWriter @ "
    238                     + out.dataPosition() + ", size " + pwriter.getStringCount());
    239             pwriter.finish();
    240             mViewStack.clear();
    241             return false;
    242         }
    243 
    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);
    250             } else {
    251                 entry = mViewStack.get(pos);
    252                 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Existing stack entry at " + pos + ": " + entry);
    253             }
    254             entry.node = node;
    255             entry.numChildren = node.getChildCount();
    256             entry.curChild = 0;
    257             mCurViewStackEntry = entry;
    258         }
    259 
    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);
    267             mNumWrittenViews++;
    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);
    277             }
    278         }
    279 
    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);
    290                     return true;
    291                 }
    292 
    293                 // We are done writing children of the current view; pop off the stack.
    294                 do {
    295                     int pos = --mCurViewStackPos;
    296                     if (DEBUG_PARCEL_TREE) Log.d(TAG, "Done with " + mCurViewStackEntry.node
    297                             + "; popping up to " + pos);
    298                     if (pos < 0) {
    299                         // Reached the last view; step to next window.
    300                         if (DEBUG_PARCEL_TREE) Log.d(TAG, "Done with view hierarchy!");
    301                         mCurViewStackEntry = null;
    302                         break;
    303                     }
    304                     mCurViewStackEntry = mViewStack.get(pos);
    305                 } while (mCurViewStackEntry.curChild >= mCurViewStackEntry.numChildren);
    306                 return true;
    307             }
    308 
    309             // Write the next window if appropriate.
    310             int pos = mCurWindow;
    311             if (pos < mNumWindows) {
    312                 WindowNode win = as.mWindowNodes.get(pos);
    313                 mCurWindow++;
    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);
    324                 return true;
    325             }
    326 
    327             return false;
    328         }
    329     }
    330 
    331     final class ParcelTransferReader {
    332         final float[] mTmpMatrix = new float[9];
    333         PooledStringReader mStringReader;
    334 
    335         int mNumReadWindows;
    336         int mNumReadViews;
    337 
    338         private final IBinder mChannel;
    339         private IBinder mTransferToken;
    340         private Parcel mCurParcel;
    341 
    342         ParcelTransferReader(IBinder channel) {
    343             mChannel = channel;
    344         }
    345 
    346         void go() {
    347             fetchData();
    348             mActivityComponent = ComponentName.readFromParcel(mCurParcel);
    349             mFlags = mCurParcel.readInt();
    350             mAcquisitionStartTime = mCurParcel.readLong();
    351             mAcquisitionEndTime = mCurParcel.readLong();
    352             final int N = mCurParcel.readInt();
    353             if (N > 0) {
    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));
    361                 }
    362             }
    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.
    368         }
    369 
    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();
    375             if (token != 0) {
    376                 if (token != validateToken) {
    377                     throw new BadParcelableException("Got token " + Integer.toHexString(token)
    378                             + ", expected token " + Integer.toHexString(validateToken));
    379                 }
    380                 return mCurParcel;
    381             }
    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");
    387             }
    388             if (DEBUG_PARCEL) Log.d(TAG, "Ran out of partial data at "
    389                     + mCurParcel.dataPosition() + ", token " + mTransferToken);
    390             fetchData();
    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();
    400             return mCurParcel;
    401         }
    402 
    403         private void fetchData() {
    404             Parcel data = Parcel.obtain();
    405             try {
    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();
    411                 }
    412                 mCurParcel = Parcel.obtain();
    413                 try {
    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);
    418                 }
    419             } finally {
    420                 data.recycle();
    421             }
    422             mNumReadWindows = mNumReadViews = 0;
    423         }
    424     }
    425 
    426     final static class ViewNodeText {
    427         CharSequence mText;
    428         float mTextSize;
    429         int mTextStyle;
    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;
    436         String mHint;
    437 
    438         ViewNodeText() {
    439         }
    440 
    441         boolean isSimple() {
    442             return mTextBackgroundColor == ViewNode.TEXT_COLOR_UNDEFINED
    443                     && mTextSelectionStart == 0 && mTextSelectionEnd == 0
    444                     && mLineCharOffsets == null && mLineBaselines == null && mHint == null;
    445         }
    446 
    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();
    452             if (!simple) {
    453                 mTextBackgroundColor = in.readInt();
    454                 mTextSelectionStart = in.readInt();
    455                 mTextSelectionEnd = in.readInt();
    456                 mLineCharOffsets = in.createIntArray();
    457                 mLineBaselines = in.createIntArray();
    458                 mHint = in.readString();
    459             }
    460         }
    461 
    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);
    467             if (!simple) {
    468                 out.writeInt(mTextBackgroundColor);
    469                 out.writeInt(mTextSelectionStart);
    470                 out.writeInt(mTextSelectionEnd);
    471                 out.writeIntArray(mLineCharOffsets);
    472                 out.writeIntArray(mLineBaselines);
    473                 out.writeString(mHint);
    474             }
    475         }
    476     }
    477 
    478     /**
    479      * Describes a window in the assist data.
    480      */
    481     static public class WindowNode {
    482         final int mX;
    483         final int mY;
    484         final int mWidth;
    485         final int mHeight;
    486         final CharSequence mTitle;
    487         final int mDisplayId;
    488         final ViewNode mRoot;
    489 
    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();
    501 
    502             ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false);
    503             if ((root.getWindowFlags() & WindowManager.LayoutParams.FLAG_SECURE) != 0) {
    504                 if (forAutoFill) {
    505                     final int viewFlags = resolveViewAutofillFlags(view.getContext(), flags);
    506                     view.onProvideAutofillStructure(builder, viewFlags);
    507                 } else {
    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);
    512                     return;
    513                 }
    514             }
    515             if (forAutoFill) {
    516                 final int viewFlags = resolveViewAutofillFlags(view.getContext(), flags);
    517                 view.dispatchProvideAutofillStructure(builder, viewFlags);
    518             } else {
    519                 view.dispatchProvideStructure(builder);
    520             }
    521         }
    522 
    523         WindowNode(ParcelTransferReader reader) {
    524             Parcel in = reader.readParcel(VALIDATE_WINDOW_TOKEN, 0);
    525             reader.mNumReadWindows++;
    526             mX = in.readInt();
    527             mY = in.readInt();
    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);
    533         }
    534 
    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;
    539         }
    540 
    541         void writeSelfToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix) {
    542             out.writeInt(mX);
    543             out.writeInt(mY);
    544             out.writeInt(mWidth);
    545             out.writeInt(mHeight);
    546             TextUtils.writeToParcel(mTitle, out, 0);
    547             out.writeInt(mDisplayId);
    548         }
    549 
    550         /**
    551          * Returns the left edge of the window, in pixels, relative to the left
    552          * edge of the screen.
    553          */
    554         public int getLeft() {
    555             return mX;
    556         }
    557 
    558         /**
    559          * Returns the top edge of the window, in pixels, relative to the top
    560          * edge of the screen.
    561          */
    562         public int getTop() {
    563             return mY;
    564         }
    565 
    566         /**
    567          * Returns the total width of the window in pixels.
    568          */
    569         public int getWidth() {
    570             return mWidth;
    571         }
    572 
    573         /**
    574          * Returns the total height of the window in pixels.
    575          */
    576         public int getHeight() {
    577             return mHeight;
    578         }
    579 
    580         /**
    581          * Returns the title associated with the window, if it has one.
    582          */
    583         public CharSequence getTitle() {
    584             return mTitle;
    585         }
    586 
    587         /**
    588          * Returns the ID of the display this window is on, for use with
    589          * {@link android.hardware.display.DisplayManager#getDisplay DisplayManager.getDisplay()}.
    590          */
    591         public int getDisplayId() {
    592             return mDisplayId;
    593         }
    594 
    595         /**
    596          * Returns the {@link ViewNode} containing the root content of the window.
    597          */
    598         public ViewNode getRootViewNode() {
    599             return mRoot;
    600         }
    601     }
    602 
    603     /**
    604      * Describes a single view in the assist data.
    605      */
    606     static public class ViewNode {
    607         /**
    608          * Magic value for text color that has not been defined, which is very unlikely
    609          * to be confused with a real text color.
    610          */
    611         public static final int TEXT_COLOR_UNDEFINED = 1;
    612 
    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;
    617 
    618         int mId = View.NO_ID;
    619         String mIdPackage;
    620         String mIdType;
    621         String mIdEntry;
    622 
    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;
    630         boolean mSanitized;
    631         HtmlInfo mHtmlInfo;
    632         int mMinEms = -1;
    633         int mMaxEms = -1;
    634         int mMaxLength = -1;
    635         @Nullable String mTextIdEntry;
    636         @AutofillImportance int mImportantForAutofill;
    637 
    638         // POJO used to override some autofill-related values when the node is parcelized.
    639         // Not written to parcel.
    640         AutofillOverlay mAutofillOverlay;
    641 
    642         int mX;
    643         int mY;
    644         int mScrollX;
    645         int mScrollY;
    646         int mWidth;
    647         int mHeight;
    648         Matrix mMatrix;
    649         float mElevation;
    650         float mAlpha = 1.0f;
    651 
    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;
    666 
    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;
    687 
    688         int mFlags;
    689 
    690         String mClassName;
    691         CharSequence mContentDescription;
    692 
    693         ViewNodeText mText;
    694         int mInputType;
    695         String mWebScheme;
    696         String mWebDomain;
    697         Bundle mExtras;
    698         LocaleList mLocaleList;
    699 
    700         ViewNode[] mChildren;
    701 
    702         ViewNode() {
    703         }
    704 
    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) {
    713                 mId = in.readInt();
    714                 if (mId != View.NO_ID) {
    715                     mIdEntry = preader.readString();
    716                     if (mIdEntry != null) {
    717                         mIdType = preader.readString();
    718                         mIdPackage = preader.readString();
    719                     }
    720                 }
    721             }
    722 
    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;
    733                 }
    734                 mMinEms = in.readInt();
    735                 mMaxEms = in.readInt();
    736                 mMaxLength = in.readInt();
    737                 mTextIdEntry = preader.readString();
    738                 mImportantForAutofill = in.readInt();
    739             }
    740             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
    741                 mX = in.readInt();
    742                 mY = in.readInt();
    743                 mWidth = in.readInt();
    744                 mHeight = in.readInt();
    745             } else {
    746                 int val = in.readInt();
    747                 mX = val&0x7fff;
    748                 mY = (val>>16)&0x7fff;
    749                 val = in.readInt();
    750                 mWidth = val&0x7fff;
    751                 mHeight = (val>>16)&0x7fff;
    752             }
    753             if ((flags&FLAGS_HAS_SCROLL) != 0) {
    754                 mScrollX = in.readInt();
    755                 mScrollY = in.readInt();
    756             }
    757             if ((flags&FLAGS_HAS_MATRIX) != 0) {
    758                 mMatrix = new Matrix();
    759                 in.readFloatArray(reader.mTmpMatrix);
    760                 mMatrix.setValues(reader.mTmpMatrix);
    761             }
    762             if ((flags&FLAGS_HAS_ELEVATION) != 0) {
    763                 mElevation = in.readFloat();
    764             }
    765             if ((flags&FLAGS_HAS_ALPHA) != 0) {
    766                 mAlpha = in.readFloat();
    767             }
    768             if ((flags&FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
    769                 mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
    770             }
    771             if ((flags&FLAGS_HAS_TEXT) != 0) {
    772                 mText = new ViewNodeText(in, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0);
    773             }
    774             if ((flags&FLAGS_HAS_INPUT_TYPE) != 0) {
    775                 mInputType = in.readInt();
    776             }
    777             if ((flags&FLAGS_HAS_URL) != 0) {
    778                 mWebScheme = in.readString();
    779                 mWebDomain = in.readString();
    780             }
    781             if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
    782                 mLocaleList = in.readParcelable(null);
    783             }
    784             if ((flags&FLAGS_HAS_EXTRAS) != 0) {
    785                 mExtras = in.readBundle();
    786             }
    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);
    796                 }
    797             }
    798         }
    799 
    800         int writeSelfToParcel(Parcel out, PooledStringWriter pwriter, boolean sanitizeOnWrite,
    801                 float[] tmpMatrix) {
    802             // Guard used to skip non-sanitized data when writing for autofill.
    803             boolean writeSensitive = true;
    804 
    805             int flags = mFlags & ~FLAGS_ALL_CONTROL;
    806 
    807             if (mId != View.NO_ID) {
    808                 flags |= FLAGS_HAS_ID;
    809             }
    810             if (mAutofillId != null) {
    811                 flags |= FLAGS_HAS_AUTOFILL_DATA;
    812             }
    813             if ((mX&~0x7fff) != 0 || (mY&~0x7fff) != 0
    814                     || (mWidth&~0x7fff) != 0 | (mHeight&~0x7fff) != 0) {
    815                 flags |= FLAGS_HAS_LARGE_COORDS;
    816             }
    817             if (mScrollX != 0 || mScrollY != 0) {
    818                 flags |= FLAGS_HAS_SCROLL;
    819             }
    820             if (mMatrix != null) {
    821                 flags |= FLAGS_HAS_MATRIX;
    822             }
    823             if (mElevation != 0) {
    824                 flags |= FLAGS_HAS_ELEVATION;
    825             }
    826             if (mAlpha != 1.0f) {
    827                 flags |= FLAGS_HAS_ALPHA;
    828             }
    829             if (mContentDescription != null) {
    830                 flags |= FLAGS_HAS_CONTENT_DESCRIPTION;
    831             }
    832             if (mText != null) {
    833                 flags |= FLAGS_HAS_TEXT;
    834                 if (!mText.isSimple()) {
    835                     flags |= FLAGS_HAS_COMPLEX_TEXT;
    836                 }
    837             }
    838             if (mInputType != 0) {
    839                 flags |= FLAGS_HAS_INPUT_TYPE;
    840             }
    841             if (mWebScheme != null || mWebDomain != null) {
    842                 flags |= FLAGS_HAS_URL;
    843             }
    844             if (mLocaleList != null) {
    845                 flags |= FLAGS_HAS_LOCALE_LIST;
    846             }
    847             if (mExtras != null) {
    848                 flags |= FLAGS_HAS_EXTRAS;
    849             }
    850             if (mChildren != null) {
    851                 flags |= FLAGS_HAS_CHILDREN;
    852             }
    853 
    854             pwriter.writeString(mClassName);
    855 
    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;
    860             }
    861             if (mAutofillOverlay != null) {
    862                 if (mAutofillOverlay.focused) {
    863                     writtenFlags |= ViewNode.FLAGS_FOCUSED;
    864                 } else {
    865                     writtenFlags &= ~ViewNode.FLAGS_FOCUSED;
    866                 }
    867             }
    868 
    869             out.writeInt(writtenFlags);
    870             if ((flags&FLAGS_HAS_ID) != 0) {
    871                 out.writeInt(mId);
    872                 if (mId != View.NO_ID) {
    873                     pwriter.writeString(mIdEntry);
    874                     if (mIdEntry != null) {
    875                         pwriter.writeString(mIdType);
    876                         pwriter.writeString(mIdPackage);
    877                     }
    878                 }
    879             }
    880 
    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;
    892                 } else {
    893                     sanitizedValue = null;
    894                 }
    895                 out.writeParcelable(sanitizedValue,  0);
    896                 out.writeCharSequenceArray(mAutofillOptions);
    897                 if (mHtmlInfo instanceof Parcelable) {
    898                     out.writeParcelable((Parcelable) mHtmlInfo, 0);
    899                 } else {
    900                     out.writeParcelable(null, 0);
    901                 }
    902                 out.writeInt(mMinEms);
    903                 out.writeInt(mMaxEms);
    904                 out.writeInt(mMaxLength);
    905                 pwriter.writeString(mTextIdEntry);
    906                 out.writeInt(mImportantForAutofill);
    907             }
    908             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
    909                 out.writeInt(mX);
    910                 out.writeInt(mY);
    911                 out.writeInt(mWidth);
    912                 out.writeInt(mHeight);
    913             } else {
    914                 out.writeInt((mY<<16) | mX);
    915                 out.writeInt((mHeight<<16) | mWidth);
    916             }
    917             if ((flags&FLAGS_HAS_SCROLL) != 0) {
    918                 out.writeInt(mScrollX);
    919                 out.writeInt(mScrollY);
    920             }
    921             if ((flags&FLAGS_HAS_MATRIX) != 0) {
    922                 mMatrix.getValues(tmpMatrix);
    923                 out.writeFloatArray(tmpMatrix);
    924             }
    925             if ((flags&FLAGS_HAS_ELEVATION) != 0) {
    926                 out.writeFloat(mElevation);
    927             }
    928             if ((flags&FLAGS_HAS_ALPHA) != 0) {
    929                 out.writeFloat(mAlpha);
    930             }
    931             if ((flags&FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
    932                 TextUtils.writeToParcel(mContentDescription, out, 0);
    933             }
    934             if ((flags&FLAGS_HAS_TEXT) != 0) {
    935                 mText.writeToParcel(out, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0, writeSensitive);
    936             }
    937             if ((flags&FLAGS_HAS_INPUT_TYPE) != 0) {
    938                 out.writeInt(mInputType);
    939             }
    940             if ((flags&FLAGS_HAS_URL) != 0) {
    941                 out.writeString(mWebScheme);
    942                 out.writeString(mWebDomain);
    943             }
    944             if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
    945                 out.writeParcelable(mLocaleList, 0);
    946             }
    947             if ((flags&FLAGS_HAS_EXTRAS) != 0) {
    948                 out.writeBundle(mExtras);
    949             }
    950             return flags;
    951         }
    952 
    953         /**
    954          * Returns the ID associated with this view, as per {@link View#getId() View.getId()}.
    955          */
    956         public int getId() {
    957             return mId;
    958         }
    959 
    960         /**
    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.
    964          */
    965         public String getIdPackage() {
    966             return mIdPackage;
    967         }
    968 
    969         /**
    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.
    973          */
    974         public String getIdType() {
    975             return mIdType;
    976         }
    977 
    978         /**
    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.
    982          */
    983         public String getIdEntry() {
    984             return mIdEntry;
    985         }
    986 
    987         /**
    988          * Gets the id that can be used to autofill the view contents.
    989          *
    990          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes.
    991          *
    992          * @return id that can be used to autofill the view contents, or {@code null} if the
    993          * structure was created for assist purposes.
    994          */
    995         @Nullable public AutofillId getAutofillId() {
    996             return mAutofillId;
    997         }
    998 
    999         /**
   1000          * Gets the the type of value that can be used to autofill the view contents.
   1001          *
   1002          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes.
   1003          *
   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.
   1006          */
   1007         public @View.AutofillType int getAutofillType() {
   1008             return mAutofillType;
   1009         }
   1010 
   1011         /**
   1012          * Describes the content of a view so that a autofill service can fill in the appropriate
   1013          * data.
   1014          *
   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.
   1017          *
   1018          * @return The autofill hints for this view, or {@code null} if the structure was created
   1019          * for assist purposes.
   1020          */
   1021         @Nullable public String[] getAutofillHints() {
   1022             return mAutofillHints;
   1023         }
   1024 
   1025         /**
   1026          * Gets the the value of this view.
   1027          *
   1028          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
   1029          * not for assist purposes.
   1030          *
   1031          * @return the autofill value of this view, or {@code null} if the structure was created
   1032          * for assist purposes.
   1033          */
   1034         @Nullable public AutofillValue getAutofillValue() {
   1035             return mAutofillValue;
   1036         }
   1037 
   1038         /** @hide **/
   1039         public void setAutofillOverlay(AutofillOverlay overlay) {
   1040             mAutofillOverlay = overlay;
   1041         }
   1042 
   1043         /**
   1044          * Gets the options that can be used to autofill this view.
   1045          *
   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.
   1048          *
   1049          * <p>It's relevant when the {@link AssistStructure} is used for autofill purposes, not
   1050          * for assist purposes.
   1051          *
   1052          * @return the options that can be used to autofill this view, or {@code null} if the
   1053          * structure was created for assist purposes.
   1054          */
   1055         @Nullable public CharSequence[] getAutofillOptions() {
   1056             return mAutofillOptions;
   1057         }
   1058 
   1059         /**
   1060          * Gets the {@link android.text.InputType} bits of this structure.
   1061          *
   1062          * @return bits as defined by {@link android.text.InputType}.
   1063          */
   1064         public int getInputType() {
   1065             return mInputType;
   1066         }
   1067 
   1068         /** @hide */
   1069         public boolean isSanitized() {
   1070             return mSanitized;
   1071         }
   1072 
   1073         /**
   1074          * Updates the {@link AutofillValue} of this structure.
   1075          *
   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
   1078          * initial value.
   1079          *
   1080          * @hide
   1081          */
   1082         public void updateAutofillValue(AutofillValue value) {
   1083             mAutofillValue = value;
   1084             if (value.isText()) {
   1085                 if (mText == null) {
   1086                     mText = new ViewNodeText();
   1087                 }
   1088                 mText.mText = value.getTextValue();
   1089             }
   1090         }
   1091 
   1092         /**
   1093          * Returns the left edge of this view, in pixels, relative to the left edge of its parent.
   1094          */
   1095         public int getLeft() {
   1096             return mX;
   1097         }
   1098 
   1099         /**
   1100          * Returns the top edge of this view, in pixels, relative to the top edge of its parent.
   1101          */
   1102         public int getTop() {
   1103             return mY;
   1104         }
   1105 
   1106         /**
   1107          * Returns the current X scroll offset of this view, as per
   1108          * {@link android.view.View#getScrollX() View.getScrollX()}.
   1109          */
   1110         public int getScrollX() {
   1111             return mScrollX;
   1112         }
   1113 
   1114         /**
   1115          * Returns the current Y scroll offset of this view, as per
   1116          * {@link android.view.View#getScrollX() View.getScrollY()}.
   1117          */
   1118         public int getScrollY() {
   1119             return mScrollY;
   1120         }
   1121 
   1122         /**
   1123          * Returns the width of this view, in pixels.
   1124          */
   1125         public int getWidth() {
   1126             return mWidth;
   1127         }
   1128 
   1129         /**
   1130          * Returns the height of this view, in pixels.
   1131          */
   1132         public int getHeight() {
   1133             return mHeight;
   1134         }
   1135 
   1136         /**
   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.
   1140          *
   1141          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
   1142          * not for autofill purposes.
   1143          */
   1144         public Matrix getTransformation() {
   1145             return mMatrix;
   1146         }
   1147 
   1148         /**
   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)}.
   1152          *
   1153          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
   1154          * not for autofill purposes.
   1155          */
   1156         public float getElevation() {
   1157             return mElevation;
   1158         }
   1159 
   1160         /**
   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)}.
   1164          *
   1165          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
   1166          * not for autofill purposes.
   1167          */
   1168         public float getAlpha() {
   1169             return mAlpha;
   1170         }
   1171 
   1172         /**
   1173          * Returns the visibility mode of this view, as per
   1174          * {@link android.view.View#getVisibility() View.getVisibility()}.
   1175          */
   1176         public int getVisibility() {
   1177             return mFlags&ViewNode.FLAGS_VISIBILITY_MASK;
   1178         }
   1179 
   1180         /**
   1181          * Returns true if assist data has been blocked starting at this node in the hierarchy.
   1182          */
   1183         public boolean isAssistBlocked() {
   1184             return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) != 0;
   1185         }
   1186 
   1187         /**
   1188          * Returns true if this node is in an enabled state.
   1189          */
   1190         public boolean isEnabled() {
   1191             return (mFlags&ViewNode.FLAGS_DISABLED) == 0;
   1192         }
   1193 
   1194         /**
   1195          * Returns true if this node is clickable by the user.
   1196          */
   1197         public boolean isClickable() {
   1198             return (mFlags&ViewNode.FLAGS_CLICKABLE) != 0;
   1199         }
   1200 
   1201         /**
   1202          * Returns true if this node can take input focus.
   1203          */
   1204         public boolean isFocusable() {
   1205             return (mFlags&ViewNode.FLAGS_FOCUSABLE) != 0;
   1206         }
   1207 
   1208         /**
   1209          * Returns true if this node currently had input focus at the time that the
   1210          * structure was collected.
   1211          */
   1212         public boolean isFocused() {
   1213             return (mFlags&ViewNode.FLAGS_FOCUSED) != 0;
   1214         }
   1215 
   1216         /**
   1217          * Returns true if this node currently had accessibility focus at the time that the
   1218          * structure was collected.
   1219          */
   1220         public boolean isAccessibilityFocused() {
   1221             return (mFlags&ViewNode.FLAGS_ACCESSIBILITY_FOCUSED) != 0;
   1222         }
   1223 
   1224         /**
   1225          * Returns true if this node represents something that is checkable by the user.
   1226          */
   1227         public boolean isCheckable() {
   1228             return (mFlags&ViewNode.FLAGS_CHECKABLE) != 0;
   1229         }
   1230 
   1231         /**
   1232          * Returns true if this node is currently in a checked state.
   1233          */
   1234         public boolean isChecked() {
   1235             return (mFlags&ViewNode.FLAGS_CHECKED) != 0;
   1236         }
   1237 
   1238         /**
   1239          * Returns true if this node has currently been selected by the user.
   1240          */
   1241         public boolean isSelected() {
   1242             return (mFlags&ViewNode.FLAGS_SELECTED) != 0;
   1243         }
   1244 
   1245         /**
   1246          * Returns true if this node has currently been activated by the user.
   1247          */
   1248         public boolean isActivated() {
   1249             return (mFlags&ViewNode.FLAGS_ACTIVATED) != 0;
   1250         }
   1251 
   1252         /**
   1253          * Returns true if this node is opaque.
   1254          */
   1255         public boolean isOpaque() { return (mFlags&ViewNode.FLAGS_OPAQUE) != 0; }
   1256 
   1257         /**
   1258          * Returns true if this node is something the user can perform a long click/press on.
   1259          */
   1260         public boolean isLongClickable() {
   1261             return (mFlags&ViewNode.FLAGS_LONG_CLICKABLE) != 0;
   1262         }
   1263 
   1264         /**
   1265          * Returns true if this node is something the user can perform a context click on.
   1266          */
   1267         public boolean isContextClickable() {
   1268             return (mFlags&ViewNode.FLAGS_CONTEXT_CLICKABLE) != 0;
   1269         }
   1270 
   1271         /**
   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}.
   1275          */
   1276         public String getClassName() {
   1277             return mClassName;
   1278         }
   1279 
   1280         /**
   1281          * Returns any content description associated with the node, which semantically describes
   1282          * its purpose for accessibility and other uses.
   1283          */
   1284         public CharSequence getContentDescription() {
   1285             return mContentDescription;
   1286         }
   1287 
   1288         /**
   1289          * Returns the domain of the HTML document represented by this view.
   1290          *
   1291          * <p>Typically used when the view associated with the view is a container for an HTML
   1292          * document.
   1293          *
   1294          * <p><b>Warning:</b> an autofill service cannot trust the value reported by this method
   1295          * without verifing its authenticity&mdash;see the "Web security" section of
   1296          * {@link android.service.autofill.AutofillService} for more details.
   1297          *
   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}.
   1300          */
   1301         @Nullable public String getWebDomain() {
   1302             return mWebDomain;
   1303         }
   1304 
   1305         /**
   1306          * @hide
   1307          */
   1308         public void setWebDomain(@Nullable String domain) {
   1309             if (domain == null) return;
   1310 
   1311             final Uri uri = Uri.parse(domain);
   1312             if (uri == null) {
   1313                 // Cannot log domain because it could contain PII;
   1314                 Log.w(TAG, "Failed to parse web domain");
   1315                 return;
   1316             }
   1317             mWebScheme = uri.getScheme();
   1318             mWebDomain = uri.getHost();
   1319         }
   1320 
   1321         /**
   1322          * Returns the scheme of the HTML document represented by this view.
   1323          *
   1324          * <p>Typically used when the view associated with the view is a container for an HTML
   1325          * document.
   1326          *
   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}.
   1329          */
   1330         @Nullable public String getWebScheme() {
   1331             return mWebScheme;
   1332         }
   1333 
   1334         /**
   1335          * Returns the HTML properties associated with this view.
   1336          *
   1337          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
   1338          * not for assist purposes.
   1339          *
   1340          * @return the HTML properties associated with this view, or {@code null} if the
   1341          * structure was created for assist purposes.
   1342          */
   1343         @Nullable public HtmlInfo getHtmlInfo() {
   1344             return mHtmlInfo;
   1345         }
   1346 
   1347         /**
   1348          * Returns the the list of locales associated with this view.
   1349          */
   1350         @Nullable public LocaleList getLocaleList() {
   1351             return mLocaleList;
   1352         }
   1353 
   1354         /**
   1355          * Returns any text associated with the node that is displayed to the user, or null
   1356          * if there is none.
   1357          */
   1358         public CharSequence getText() {
   1359             return mText != null ? mText.mText : null;
   1360         }
   1361 
   1362         /**
   1363          * If {@link #getText()} is non-null, this is where the current selection starts.
   1364          *
   1365          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
   1366          * not for autofill purposes.
   1367          */
   1368         public int getTextSelectionStart() {
   1369             return mText != null ? mText.mTextSelectionStart : -1;
   1370         }
   1371 
   1372         /**
   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.
   1376          *
   1377          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
   1378          * not for autofill purposes.
   1379          */
   1380         public int getTextSelectionEnd() {
   1381             return mText != null ? mText.mTextSelectionEnd : -1;
   1382         }
   1383 
   1384         /**
   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.
   1389          */
   1390         public int getTextColor() {
   1391             return mText != null ? mText.mTextColor : TEXT_COLOR_UNDEFINED;
   1392         }
   1393 
   1394         /**
   1395          * If {@link #getText()} is non-null, this is the main text background color associated
   1396          * with it.
   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.
   1400          *
   1401          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
   1402          * not for autofill purposes.
   1403          */
   1404         public int getTextBackgroundColor() {
   1405             return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
   1406         }
   1407 
   1408         /**
   1409          * If {@link #getText()} is non-null, this is the main text size (in pixels) associated
   1410          * with it.
   1411          * Note that the text may also contain style spans that modify the size of specific
   1412          * parts of the text.
   1413          *
   1414          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
   1415          * not for autofill purposes.
   1416          */
   1417         public float getTextSize() {
   1418             return mText != null ? mText.mTextSize : 0;
   1419         }
   1420 
   1421         /**
   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.
   1428          *
   1429          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
   1430          * not for autofill purposes.
   1431          */
   1432         public int getTextStyle() {
   1433             return mText != null ? mText.mTextStyle : 0;
   1434         }
   1435 
   1436         /**
   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
   1440          * information.
   1441          *
   1442          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
   1443          * not for autofill purposes.
   1444          */
   1445         public int[] getTextLineCharOffsets() {
   1446             return mText != null ? mText.mLineCharOffsets : null;
   1447         }
   1448 
   1449         /**
   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
   1453          * information.
   1454          *
   1455          * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
   1456          * not for autofill purposes.
   1457          */
   1458         public int[] getTextLineBaselines() {
   1459             return mText != null ? mText.mLineBaselines : null;
   1460         }
   1461 
   1462         /**
   1463          * Gets the identifier used to set the text associated with this view.
   1464          *
   1465          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
   1466          * not for assist purposes.
   1467          */
   1468         @Nullable
   1469         public String getTextIdEntry() {
   1470             return mTextIdEntry;
   1471         }
   1472 
   1473         /**
   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.
   1476          */
   1477         public String getHint() {
   1478             return mText != null ? mText.mHint : null;
   1479         }
   1480 
   1481         /**
   1482          * Return a Bundle containing optional vendor-specific extension information.
   1483          */
   1484         public Bundle getExtras() {
   1485             return mExtras;
   1486         }
   1487 
   1488         /**
   1489          * Return the number of children this node has.
   1490          */
   1491         public int getChildCount() {
   1492             return mChildren != null ? mChildren.length : 0;
   1493         }
   1494 
   1495         /**
   1496          * Return a child of this node, given an index value from 0 to
   1497          * {@link #getChildCount()}-1.
   1498          */
   1499         public ViewNode getChildAt(int index) {
   1500             return mChildren[index];
   1501         }
   1502 
   1503         /**
   1504          * Returns the minimum width in ems of the text associated with this node, or {@code -1}
   1505          * if not supported by the node.
   1506          *
   1507          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
   1508          * not for assist purposes.
   1509          */
   1510         public int getMinTextEms() {
   1511             return mMinEms;
   1512         }
   1513 
   1514         /**
   1515          * Returns the maximum width in ems of the text associated with this node, or {@code -1}
   1516          * if not supported by the node.
   1517          *
   1518          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
   1519          * not for assist purposes.
   1520          */
   1521         public int getMaxTextEms() {
   1522             return mMaxEms;
   1523         }
   1524 
   1525         /**
   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.
   1528          *
   1529          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
   1530          * not for assist purposes.
   1531          */
   1532         public int getMaxTextLength() {
   1533             return mMaxLength;
   1534         }
   1535 
   1536         /**
   1537          * Gets the {@link View#setImportantForAutofill(int) importantForAutofill mode} of
   1538          * the view associated with this node.
   1539          *
   1540          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes.
   1541          */
   1542         public @AutofillImportance int getImportantForAutofill() {
   1543             return mImportantForAutofill;
   1544         }
   1545     }
   1546 
   1547     /**
   1548      * POJO used to override some autofill-related values when the node is parcelized.
   1549      *
   1550      * @hide
   1551      */
   1552     static public class AutofillOverlay {
   1553         public boolean focused;
   1554         public AutofillValue value;
   1555     }
   1556 
   1557     static class ViewNodeBuilder extends ViewStructure {
   1558         final AssistStructure mAssist;
   1559         final ViewNode mNode;
   1560         final boolean mAsync;
   1561 
   1562         ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async) {
   1563             mAssist = assist;
   1564             mNode = node;
   1565             mAsync = async;
   1566         }
   1567 
   1568         @Override
   1569         public void setId(int id, String packageName, String typeName, String entryName) {
   1570             mNode.mId = id;
   1571             mNode.mIdPackage = packageName;
   1572             mNode.mIdType = typeName;
   1573             mNode.mIdEntry = entryName;
   1574         }
   1575 
   1576         @Override
   1577         public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) {
   1578             mNode.mX = left;
   1579             mNode.mY = top;
   1580             mNode.mScrollX = scrollX;
   1581             mNode.mScrollY = scrollY;
   1582             mNode.mWidth = width;
   1583             mNode.mHeight = height;
   1584         }
   1585 
   1586         @Override
   1587         public void setTransformation(Matrix matrix) {
   1588             if (matrix == null) {
   1589                 mNode.mMatrix = null;
   1590             } else {
   1591                 mNode.mMatrix = new Matrix(matrix);
   1592             }
   1593         }
   1594 
   1595         @Override
   1596         public void setElevation(float elevation) {
   1597             mNode.mElevation = elevation;
   1598         }
   1599 
   1600         @Override
   1601         public void setAlpha(float alpha) {
   1602             mNode.mAlpha = alpha;
   1603         }
   1604 
   1605         @Override
   1606         public void setVisibility(int visibility) {
   1607             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_VISIBILITY_MASK) | visibility;
   1608         }
   1609 
   1610         @Override
   1611         public void setAssistBlocked(boolean state) {
   1612             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ASSIST_BLOCKED)
   1613                     | (state ? ViewNode.FLAGS_ASSIST_BLOCKED : 0);
   1614         }
   1615 
   1616         @Override
   1617         public void setEnabled(boolean state) {
   1618             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_DISABLED)
   1619                     | (state ? 0 : ViewNode.FLAGS_DISABLED);
   1620         }
   1621 
   1622         @Override
   1623         public void setClickable(boolean state) {
   1624             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CLICKABLE)
   1625                     | (state ? ViewNode.FLAGS_CLICKABLE : 0);
   1626         }
   1627 
   1628         @Override
   1629         public void setLongClickable(boolean state) {
   1630             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_LONG_CLICKABLE)
   1631                     | (state ? ViewNode.FLAGS_LONG_CLICKABLE : 0);
   1632         }
   1633 
   1634         @Override
   1635         public void setContextClickable(boolean state) {
   1636             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CONTEXT_CLICKABLE)
   1637                     | (state ? ViewNode.FLAGS_CONTEXT_CLICKABLE : 0);
   1638         }
   1639 
   1640         @Override
   1641         public void setFocusable(boolean state) {
   1642             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSABLE)
   1643                     | (state ? ViewNode.FLAGS_FOCUSABLE : 0);
   1644         }
   1645 
   1646         @Override
   1647         public void setFocused(boolean state) {
   1648             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSED)
   1649                     | (state ? ViewNode.FLAGS_FOCUSED : 0);
   1650         }
   1651 
   1652         @Override
   1653         public void setAccessibilityFocused(boolean state) {
   1654             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACCESSIBILITY_FOCUSED)
   1655                     | (state ? ViewNode.FLAGS_ACCESSIBILITY_FOCUSED : 0);
   1656         }
   1657 
   1658         @Override
   1659         public void setCheckable(boolean state) {
   1660             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKABLE)
   1661                     | (state ? ViewNode.FLAGS_CHECKABLE : 0);
   1662         }
   1663 
   1664         @Override
   1665         public void setChecked(boolean state) {
   1666             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKED)
   1667                     | (state ? ViewNode.FLAGS_CHECKED : 0);
   1668         }
   1669 
   1670         @Override
   1671         public void setSelected(boolean state) {
   1672             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_SELECTED)
   1673                     | (state ? ViewNode.FLAGS_SELECTED : 0);
   1674         }
   1675 
   1676         @Override
   1677         public void setActivated(boolean state) {
   1678             mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACTIVATED)
   1679                     | (state ? ViewNode.FLAGS_ACTIVATED : 0);
   1680         }
   1681 
   1682         @Override
   1683         public void setOpaque(boolean opaque) {
   1684             mNode.mFlags = (mNode.mFlags & ~ViewNode.FLAGS_OPAQUE)
   1685                     | (opaque ? ViewNode.FLAGS_OPAQUE : 0);
   1686         }
   1687 
   1688         @Override
   1689         public void setClassName(String className) {
   1690             mNode.mClassName = className;
   1691         }
   1692 
   1693         @Override
   1694         public void setContentDescription(CharSequence contentDescription) {
   1695             mNode.mContentDescription = contentDescription;
   1696         }
   1697 
   1698         private final ViewNodeText getNodeText() {
   1699             if (mNode.mText != null) {
   1700                 return mNode.mText;
   1701             }
   1702             mNode.mText = new ViewNodeText();
   1703             return mNode.mText;
   1704         }
   1705 
   1706         @Override
   1707         public void setText(CharSequence text) {
   1708             ViewNodeText t = getNodeText();
   1709             t.mText = TextUtils.trimNoCopySpans(text);
   1710             t.mTextSelectionStart = t.mTextSelectionEnd = -1;
   1711         }
   1712 
   1713         @Override
   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;
   1719         }
   1720 
   1721         @Override
   1722         public void setTextStyle(float size, int fgColor, int bgColor, int style) {
   1723             ViewNodeText t = getNodeText();
   1724             t.mTextColor = fgColor;
   1725             t.mTextBackgroundColor = bgColor;
   1726             t.mTextSize = size;
   1727             t.mTextStyle = style;
   1728         }
   1729 
   1730         @Override
   1731         public void setTextLines(int[] charOffsets, int[] baselines) {
   1732             ViewNodeText t = getNodeText();
   1733             t.mLineCharOffsets = charOffsets;
   1734             t.mLineBaselines = baselines;
   1735         }
   1736 
   1737         @Override
   1738         public void setTextIdEntry(@NonNull String entryName) {
   1739             mNode.mTextIdEntry = Preconditions.checkNotNull(entryName);
   1740         }
   1741 
   1742         @Override
   1743         public void setHint(CharSequence hint) {
   1744             getNodeText().mHint = hint != null ? hint.toString() : null;
   1745         }
   1746 
   1747         @Override
   1748         public CharSequence getText() {
   1749             return mNode.mText != null ? mNode.mText.mText : null;
   1750         }
   1751 
   1752         @Override
   1753         public int getTextSelectionStart() {
   1754             return mNode.mText != null ? mNode.mText.mTextSelectionStart : -1;
   1755         }
   1756 
   1757         @Override
   1758         public int getTextSelectionEnd() {
   1759             return mNode.mText != null ? mNode.mText.mTextSelectionEnd : -1;
   1760         }
   1761 
   1762         @Override
   1763         public CharSequence getHint() {
   1764             return mNode.mText != null ? mNode.mText.mHint : null;
   1765         }
   1766 
   1767         @Override
   1768         public Bundle getExtras() {
   1769             if (mNode.mExtras != null) {
   1770                 return mNode.mExtras;
   1771             }
   1772             mNode.mExtras = new Bundle();
   1773             return mNode.mExtras;
   1774         }
   1775 
   1776         @Override
   1777         public boolean hasExtras() {
   1778             return mNode.mExtras != null;
   1779         }
   1780 
   1781         @Override
   1782         public void setChildCount(int num) {
   1783             mNode.mChildren = new ViewNode[num];
   1784         }
   1785 
   1786         @Override
   1787         public int addChildCount(int num) {
   1788             if (mNode.mChildren == null) {
   1789                 setChildCount(num);
   1790                 return 0;
   1791             }
   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;
   1796             return start;
   1797         }
   1798 
   1799         @Override
   1800         public int getChildCount() {
   1801             return mNode.mChildren != null ? mNode.mChildren.length : 0;
   1802         }
   1803 
   1804         @Override
   1805         public ViewStructure newChild(int index) {
   1806             ViewNode node = new ViewNode();
   1807             mNode.mChildren[index] = node;
   1808             return new ViewNodeBuilder(mAssist, node, false);
   1809         }
   1810 
   1811         @Override
   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);
   1818                 return builder;
   1819             }
   1820         }
   1821 
   1822         @Override
   1823         public void asyncCommit() {
   1824             synchronized (mAssist) {
   1825                 if (!mAsync) {
   1826                     throw new IllegalStateException("Child " + this
   1827                             + " was not created with ViewStructure.asyncNewChild");
   1828                 }
   1829                 if (!mAssist.mPendingAsyncChildren.remove(this)) {
   1830                     throw new IllegalStateException("Child " + this + " already committed");
   1831                 }
   1832                 mAssist.notifyAll();
   1833             }
   1834         }
   1835 
   1836         @Override
   1837         public Rect getTempRect() {
   1838             return mAssist.mTmpRect;
   1839         }
   1840 
   1841         @Override
   1842         public void setAutofillId(@NonNull AutofillId id) {
   1843             mNode.mAutofillId = id;
   1844         }
   1845 
   1846         @Override
   1847         public void setAutofillId(@NonNull AutofillId parentId, int virtualId) {
   1848             mNode.mAutofillId = new AutofillId(parentId, virtualId);
   1849         }
   1850 
   1851         @Override
   1852         public AutofillId getAutofillId() {
   1853             return mNode.mAutofillId;
   1854         }
   1855 
   1856         @Override
   1857         public void setAutofillType(@View.AutofillType int type) {
   1858             mNode.mAutofillType = type;
   1859         }
   1860 
   1861         @Override
   1862         public void setAutofillHints(@Nullable String[] hints) {
   1863             mNode.mAutofillHints = hints;
   1864         }
   1865 
   1866         @Override
   1867         public void setAutofillValue(AutofillValue value) {
   1868             mNode.mAutofillValue = value;
   1869         }
   1870 
   1871         @Override
   1872         public void setAutofillOptions(CharSequence[] options) {
   1873             mNode.mAutofillOptions = options;
   1874         }
   1875 
   1876         @Override
   1877         public void setImportantForAutofill(@AutofillImportance int mode) {
   1878             mNode.mImportantForAutofill = mode;
   1879         }
   1880 
   1881         @Override
   1882         public void setInputType(int inputType) {
   1883             mNode.mInputType = inputType;
   1884         }
   1885 
   1886         @Override
   1887         public void setMinTextEms(int minEms) {
   1888             mNode.mMinEms = minEms;
   1889         }
   1890 
   1891         @Override
   1892         public void setMaxTextEms(int maxEms) {
   1893             mNode.mMaxEms = maxEms;
   1894         }
   1895 
   1896         @Override
   1897         public void setMaxTextLength(int maxLength) {
   1898             mNode.mMaxLength = maxLength;
   1899         }
   1900 
   1901         @Override
   1902         public void setDataIsSensitive(boolean sensitive) {
   1903             mNode.mSanitized = !sensitive;
   1904         }
   1905 
   1906         @Override
   1907         public void setWebDomain(@Nullable String domain) {
   1908             mNode.setWebDomain(domain);
   1909         }
   1910 
   1911         @Override
   1912         public void setLocaleList(LocaleList localeList) {
   1913             mNode.mLocaleList = localeList;
   1914         }
   1915 
   1916         @Override
   1917         public HtmlInfo.Builder newHtmlInfoBuilder(@NonNull String tagName) {
   1918             return new HtmlInfoNodeBuilder(tagName);
   1919         }
   1920 
   1921         @Override
   1922         public void setHtmlInfo(@NonNull HtmlInfo htmlInfo) {
   1923             mNode.mHtmlInfo = htmlInfo;
   1924         }
   1925     }
   1926 
   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;
   1931 
   1932         // Not parcelable
   1933         private ArrayList<Pair<String, String>> mAttributes;
   1934 
   1935         private HtmlInfoNode(HtmlInfoNodeBuilder builder) {
   1936             mTag = builder.mTag;
   1937             if (builder.mNames == null) {
   1938                 mNames = null;
   1939                 mValues = null;
   1940             } else {
   1941                 mNames = new String[builder.mNames.size()];
   1942                 mValues = new String[builder.mValues.size()];
   1943                 builder.mNames.toArray(mNames);
   1944                 builder.mValues.toArray(mValues);
   1945             }
   1946         }
   1947 
   1948         @Override
   1949         public String getTag() {
   1950             return mTag;
   1951         }
   1952 
   1953         @Override
   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);
   1960                 }
   1961             }
   1962             return mAttributes;
   1963         }
   1964 
   1965         @Override
   1966         public int describeContents() {
   1967             return 0;
   1968         }
   1969 
   1970         @Override
   1971         public void writeToParcel(Parcel parcel, int flags) {
   1972             parcel.writeString(mTag);
   1973             parcel.writeStringArray(mNames);
   1974             parcel.writeStringArray(mValues);
   1975         }
   1976 
   1977         @SuppressWarnings("hiding")
   1978         public static final Creator<HtmlInfoNode> CREATOR = new Creator<HtmlInfoNode>() {
   1979             @Override
   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);
   1992                     } else {
   1993                         for (int i = 0; i < names.length; i++) {
   1994                             builder.addAttribute(names[i], values[i]);
   1995                         }
   1996                     }
   1997                 }
   1998                 return builder.build();
   1999             }
   2000 
   2001             @Override
   2002             public HtmlInfoNode[] newArray(int size) {
   2003                 return new HtmlInfoNode[size];
   2004             }
   2005         };
   2006     }
   2007 
   2008     private static final class HtmlInfoNodeBuilder extends HtmlInfo.Builder {
   2009         private final String mTag;
   2010         private ArrayList<String> mNames;
   2011         private ArrayList<String> mValues;
   2012 
   2013         HtmlInfoNodeBuilder(String tag) {
   2014             mTag = tag;
   2015         }
   2016 
   2017         @Override
   2018         public Builder addAttribute(String name, String value) {
   2019             if (mNames == null) {
   2020                 mNames = new ArrayList<>();
   2021                 mValues = new ArrayList<>();
   2022             }
   2023             mNames.add(name);
   2024             mValues.add(value);
   2025             return this;
   2026         }
   2027 
   2028         @Override
   2029         public HtmlInfoNode build() {
   2030             return new HtmlInfoNode(this);
   2031         }
   2032     }
   2033 
   2034     /** @hide */
   2035     public AssistStructure(Activity activity, boolean forAutoFill, int flags) {
   2036         mHaveData = true;
   2037         mActivityComponent = activity.getComponentName();
   2038         mFlags = flags;
   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());
   2045                 continue;
   2046             }
   2047             mWindowNodes.add(new WindowNode(this, root, forAutoFill, flags));
   2048         }
   2049     }
   2050 
   2051     public AssistStructure() {
   2052         mHaveData = true;
   2053         mActivityComponent = null;
   2054         mFlags = 0;
   2055     }
   2056 
   2057     /** @hide */
   2058     public AssistStructure(Parcel in) {
   2059         mIsHomeActivity = in.readInt() == 1;
   2060         mReceiveChannel = in.readStrongBinder();
   2061     }
   2062 
   2063     /**
   2064      * Helper method used to sanitize the structure before it's written to a parcel.
   2065      *
   2066      * <p>Used just on autofill.
   2067      * @hide
   2068      */
   2069     public void sanitizeForParceling(boolean sanitize) {
   2070         mSanitizeOnWrite = sanitize;
   2071     }
   2072 
   2073     /** @hide */
   2074     public void dump(boolean showSensitive) {
   2075         if (mActivityComponent == null) {
   2076             Log.i(TAG, "dump(): calling ensureData() first");
   2077             ensureData();
   2078         }
   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);
   2088         }
   2089     }
   2090 
   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();
   2095         if (id != 0) {
   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);
   2104             }
   2105             Log.i(TAG, sb.toString());
   2106         }
   2107         int scrollX = node.getScrollX();
   2108         int scrollY = node.getScrollY();
   2109         if (scrollX != 0 || scrollY != 0) {
   2110             Log.i(TAG, prefix + "  Scroll: " + scrollX + "," + scrollY);
   2111         }
   2112         Matrix matrix = node.getTransformation();
   2113         if (matrix != null) {
   2114             Log.i(TAG, prefix + "  Transformation: " + matrix);
   2115         }
   2116         float elevation = node.getElevation();
   2117         if (elevation != 0) {
   2118             Log.i(TAG, prefix + "  Elevation: " + elevation);
   2119         }
   2120         float alpha = node.getAlpha();
   2121         if (alpha != 0) {
   2122             Log.i(TAG, prefix + "  Alpha: " + elevation);
   2123         }
   2124         CharSequence contentDescription = node.getContentDescription();
   2125         if (contentDescription != null) {
   2126             Log.i(TAG, prefix + "  Content description: " + contentDescription);
   2127         }
   2128         CharSequence text = node.getText();
   2129         if (text != null) {
   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());
   2140         }
   2141         String webDomain = node.getWebDomain();
   2142         if (webDomain != null) {
   2143             Log.i(TAG, prefix + "  Web domain: " + webDomain);
   2144         }
   2145         HtmlInfo htmlInfo = node.getHtmlInfo();
   2146         if (htmlInfo != null) {
   2147             Log.i(TAG, prefix + "  HtmlInfo: tag=" + htmlInfo.getTag()
   2148                     + ", attr="+ htmlInfo.getAttributes());
   2149         }
   2150 
   2151         LocaleList localeList = node.getLocaleList();
   2152         if (localeList != null) {
   2153             Log.i(TAG, prefix + "  LocaleList: " + localeList);
   2154         }
   2155         String hint = node.getHint();
   2156         if (hint != null) {
   2157             Log.i(TAG, prefix + "  Hint: " + hint);
   2158         }
   2159         Bundle extras = node.getExtras();
   2160         if (extras != null) {
   2161             Log.i(TAG, prefix + "  Extras: " + extras);
   2162         }
   2163         if (node.isAssistBlocked()) {
   2164             Log.i(TAG, prefix + "  BLOCKED");
   2165         }
   2166         AutofillId autofillId = node.getAutofillId();
   2167         if (autofillId == null) {
   2168             Log.i(TAG, prefix + " NO autofill ID");
   2169         } else {
   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());
   2177         }
   2178 
   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);
   2186             }
   2187         }
   2188     }
   2189 
   2190     /**
   2191      * Return the activity this AssistStructure came from.
   2192      */
   2193     public ComponentName getActivityComponent() {
   2194         ensureData();
   2195         return mActivityComponent;
   2196     }
   2197 
   2198     /**
   2199      * Called by Autofill server when app forged a different value.
   2200      *
   2201      * @hide
   2202      */
   2203     public void setActivityComponent(ComponentName componentName) {
   2204         ensureData();
   2205         mActivityComponent = componentName;
   2206     }
   2207 
   2208     /** @hide */
   2209     public int getFlags() {
   2210         return mFlags;
   2211     }
   2212 
   2213     /**
   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
   2218      */
   2219     public boolean isHomeActivity() {
   2220         return mIsHomeActivity;
   2221     }
   2222 
   2223     /**
   2224      * Return the number of window contents that have been collected in this assist data.
   2225      */
   2226     public int getWindowNodeCount() {
   2227         ensureData();
   2228         return mWindowNodes.size();
   2229     }
   2230 
   2231     /**
   2232      * Return one of the windows in the assist data.
   2233      * @param index Which window to retrieve, may be 0 to {@link #getWindowNodeCount()}-1.
   2234      */
   2235     public WindowNode getWindowNodeAt(int index) {
   2236         ensureData();
   2237         return mWindowNodes.get(index);
   2238     }
   2239 
   2240     // TODO(b/35708678): temporary method that disable one-way warning flag on binder.
   2241     /** @hide */
   2242     public void ensureDataForAutofill() {
   2243         if (mHaveData) {
   2244             return;
   2245         }
   2246         mHaveData = true;
   2247         Binder.allowBlocking(mReceiveChannel);
   2248         try {
   2249             ParcelTransferReader reader = new ParcelTransferReader(mReceiveChannel);
   2250             reader.go();
   2251         } finally {
   2252             Binder.defaultBlocking(mReceiveChannel);
   2253         }
   2254     }
   2255 
   2256     /** @hide */
   2257     public void ensureData() {
   2258         if (mHaveData) {
   2259             return;
   2260         }
   2261         mHaveData = true;
   2262         ParcelTransferReader reader = new ParcelTransferReader(mReceiveChannel);
   2263         reader.go();
   2264     }
   2265 
   2266     boolean waitForReady() {
   2267         boolean skipStructure = false;
   2268         synchronized (this) {
   2269             long endTime = SystemClock.uptimeMillis() + 5000;
   2270             long now;
   2271             while (mPendingAsyncChildren.size() > 0 && (now=SystemClock.uptimeMillis()) < endTime) {
   2272                 try {
   2273                     wait(endTime-now);
   2274                 } catch (InterruptedException e) {
   2275                 }
   2276             }
   2277             if (mPendingAsyncChildren.size() > 0) {
   2278                 // We waited too long, assume none of the assist structure is valid.
   2279                 Log.w(TAG, "Skipping assist structure, waiting too long for async children (have "
   2280                         + mPendingAsyncChildren.size() + " remaining");
   2281                 skipStructure = true;
   2282             }
   2283         }
   2284         return !skipStructure;
   2285     }
   2286 
   2287     /** @hide */
   2288     public void clearSendChannel() {
   2289         if (mSendChannel != null) {
   2290             mSendChannel.mAssistStructure = null;
   2291         }
   2292     }
   2293 
   2294     @Override
   2295     public int describeContents() {
   2296         return 0;
   2297     }
   2298 
   2299     @Override
   2300     public void writeToParcel(Parcel out, int flags) {
   2301         out.writeInt(mIsHomeActivity ? 1 : 0);
   2302         if (mHaveData) {
   2303             // This object holds its data.  We want to write a send channel that the
   2304             // other side can use to retrieve that data.
   2305             if (mSendChannel == null) {
   2306                 mSendChannel = new SendChannel(this);
   2307             }
   2308             out.writeStrongBinder(mSendChannel);
   2309         } else {
   2310             // This object doesn't hold its data, so just propagate along its receive channel.
   2311             out.writeStrongBinder(mReceiveChannel);
   2312         }
   2313     }
   2314 
   2315     public static final Parcelable.Creator<AssistStructure> CREATOR
   2316             = new Parcelable.Creator<AssistStructure>() {
   2317         @Override
   2318         public AssistStructure createFromParcel(Parcel in) {
   2319             return new AssistStructure(in);
   2320         }
   2321 
   2322         @Override
   2323         public AssistStructure[] newArray(int size) {
   2324             return new AssistStructure[size];
   2325         }
   2326     };
   2327 }
   2328