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