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 */ setAcquisitionStartTime(long acquisitionStartTime)86 public void setAcquisitionStartTime(long acquisitionStartTime) { 87 mAcquisitionStartTime = acquisitionStartTime; 88 } 89 90 /** @hide */ setAcquisitionEndTime(long acquisitionEndTime)91 public void setAcquisitionEndTime(long acquisitionEndTime) { 92 mAcquisitionEndTime = acquisitionEndTime; 93 } 94 95 /** 96 * @hide 97 * Set the home activity flag. 98 */ setHomeActivity(boolean isHomeActivity)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 */ getAcquisitionStartTime()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 */ getAcquisitionEndTime()122 public long getAcquisitionEndTime() { 123 ensureData(); 124 return mAcquisitionEndTime; 125 } 126 127 final static class SendChannel extends Binder { 128 volatile AssistStructure mAssistStructure; 129 SendChannel(AssistStructure as)130 SendChannel(AssistStructure as) { 131 mAssistStructure = as; 132 } 133 onTransact(int code, Parcel data, Parcel reply, int flags)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 ParcelTransferWriter(AssistStructure as, Parcel out)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 writeToParcel(AssistStructure as, Parcel out)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 writeToParcelInner(AssistStructure as, Parcel out)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 pushViewStackEntry(ViewNode node, int pos)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 writeView(ViewNode child, Parcel out, PooledStringWriter pwriter, int levelAdj)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 writeNextEntryToParcel(AssistStructure as, Parcel out, PooledStringWriter pwriter)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 ParcelTransferReader(IBinder channel)338 ParcelTransferReader(IBinder channel) { 339 mChannel = channel; 340 } 341 go()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 readParcel(int validateToken, int level)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 fetchData()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 ViewNodeText()429 ViewNodeText() { 430 } 431 isSimple()432 boolean isSimple() { 433 return mTextBackgroundColor == ViewNode.TEXT_COLOR_UNDEFINED 434 && mTextSelectionStart == 0 && mTextSelectionEnd == 0 435 && mLineCharOffsets == null && mLineBaselines == null && mHint == null; 436 } 437 ViewNodeText(Parcel in, boolean simple)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 writeToParcel(Parcel out, boolean simple, boolean writeSensitive)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 WindowNode(AssistStructure assist, ViewRootImpl root, boolean forAutoFill, int flags)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 WindowNode(ParcelTransferReader reader)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 writeSelfToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix)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 */ getLeft()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 */ getTop()549 public int getTop() { 550 return mY; 551 } 552 553 /** 554 * Returns the total width of the window in pixels. 555 */ getWidth()556 public int getWidth() { 557 return mWidth; 558 } 559 560 /** 561 * Returns the total height of the window in pixels. 562 */ getHeight()563 public int getHeight() { 564 return mHeight; 565 } 566 567 /** 568 * Returns the title associated with the window, if it has one. 569 */ getTitle()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 */ getDisplayId()578 public int getDisplayId() { 579 return mDisplayId; 580 } 581 582 /** 583 * Returns the {@link ViewNode} containing the root content of the window. 584 */ getRootViewNode()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 ViewNode()683 ViewNode() { 684 } 685 ViewNode(ParcelTransferReader reader, int nestingLevel)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 writeSelfToParcel(Parcel out, PooledStringWriter pwriter, boolean sanitizeOnWrite, float[] tmpMatrix)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 */ getId()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 */ getIdPackage()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 */ getIdType()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 */ getIdEntry()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 */ getAutofillId()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 */ getAutofillType()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 */ getAutofillHints()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 */ getAutofillValue()1003 @Nullable public AutofillValue getAutofillValue() { 1004 return mAutofillValue; 1005 } 1006 1007 /** @hide **/ setAutofillOverlay(AutofillOverlay overlay)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 */ getAutofillOptions()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 */ getInputType()1033 public int getInputType() { 1034 return mInputType; 1035 } 1036 1037 /** @hide */ isSanitized()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 */ updateAutofillValue(AutofillValue value)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 */ getLeft()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 */ getTop()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 */ getScrollX()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 */ getScrollY()1087 public int getScrollY() { 1088 return mScrollY; 1089 } 1090 1091 /** 1092 * Returns the width of this view, in pixels. 1093 */ getWidth()1094 public int getWidth() { 1095 return mWidth; 1096 } 1097 1098 /** 1099 * Returns the height of this view, in pixels. 1100 */ getHeight()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 */ getTransformation()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 */ getElevation()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 */ getAlpha()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 */ getVisibility()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 */ isAssistBlocked()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 */ isEnabled()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 */ isClickable()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 */ isFocusable()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 */ isFocused()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 */ isAccessibilityFocused()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 */ isCheckable()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 */ isChecked()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 */ isSelected()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 */ isActivated()1217 public boolean isActivated() { 1218 return (mFlags&ViewNode.FLAGS_ACTIVATED) != 0; 1219 } 1220 1221 /** 1222 * Returns true if this node is opaque. 1223 */ isOpaque()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 */ isLongClickable()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 */ isContextClickable()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 */ getClassName()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 */ getContentDescription()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 * <p><b>Warning:</b> an autofill service cannot trust the value reported by this method 1264 * without verifing its authenticity—see the "Web security" section of 1265 * {@link android.service.autofill.AutofillService} for more details. 1266 * 1267 * @return domain-only part of the document. For example, if the full URL is 1268 * {@code https://example.com/login?user=my_user}, it returns {@code example.com}. 1269 */ getWebDomain()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 */ getHtmlInfo()1283 @Nullable public HtmlInfo getHtmlInfo() { 1284 return mHtmlInfo; 1285 } 1286 1287 /** 1288 * Returns the the list of locales associated with this view. 1289 */ getLocaleList()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 */ getText()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 */ getTextSelectionStart()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 */ getTextSelectionEnd()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 */ getTextColor()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 */ getTextBackgroundColor()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 */ getTextSize()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 */ getTextStyle()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 */ getTextLineCharOffsets()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 */ getTextLineBaselines()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 */ getHint()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 */ getExtras()1413 public Bundle getExtras() { 1414 return mExtras; 1415 } 1416 1417 /** 1418 * Return the number of children this node has. 1419 */ getChildCount()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 */ getChildAt(int index)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 ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async)1448 ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async) { 1449 mAssist = assist; 1450 mNode = node; 1451 mAsync = async; 1452 } 1453 1454 @Override setId(int id, String packageName, String typeName, String entryName)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 setDimens(int left, int top, int scrollX, int scrollY, int width, int height)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 setTransformation(Matrix matrix)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 setElevation(float elevation)1482 public void setElevation(float elevation) { 1483 mNode.mElevation = elevation; 1484 } 1485 1486 @Override setAlpha(float alpha)1487 public void setAlpha(float alpha) { 1488 mNode.mAlpha = alpha; 1489 } 1490 1491 @Override setVisibility(int visibility)1492 public void setVisibility(int visibility) { 1493 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_VISIBILITY_MASK) | visibility; 1494 } 1495 1496 @Override setAssistBlocked(boolean state)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 setEnabled(boolean state)1503 public void setEnabled(boolean state) { 1504 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_DISABLED) 1505 | (state ? 0 : ViewNode.FLAGS_DISABLED); 1506 } 1507 1508 @Override setClickable(boolean state)1509 public void setClickable(boolean state) { 1510 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CLICKABLE) 1511 | (state ? ViewNode.FLAGS_CLICKABLE : 0); 1512 } 1513 1514 @Override setLongClickable(boolean state)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 setContextClickable(boolean state)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 setFocusable(boolean state)1527 public void setFocusable(boolean state) { 1528 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSABLE) 1529 | (state ? ViewNode.FLAGS_FOCUSABLE : 0); 1530 } 1531 1532 @Override setFocused(boolean state)1533 public void setFocused(boolean state) { 1534 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSED) 1535 | (state ? ViewNode.FLAGS_FOCUSED : 0); 1536 } 1537 1538 @Override setAccessibilityFocused(boolean state)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 setCheckable(boolean state)1545 public void setCheckable(boolean state) { 1546 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKABLE) 1547 | (state ? ViewNode.FLAGS_CHECKABLE : 0); 1548 } 1549 1550 @Override setChecked(boolean state)1551 public void setChecked(boolean state) { 1552 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKED) 1553 | (state ? ViewNode.FLAGS_CHECKED : 0); 1554 } 1555 1556 @Override setSelected(boolean state)1557 public void setSelected(boolean state) { 1558 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_SELECTED) 1559 | (state ? ViewNode.FLAGS_SELECTED : 0); 1560 } 1561 1562 @Override setActivated(boolean state)1563 public void setActivated(boolean state) { 1564 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACTIVATED) 1565 | (state ? ViewNode.FLAGS_ACTIVATED : 0); 1566 } 1567 1568 @Override setOpaque(boolean opaque)1569 public void setOpaque(boolean opaque) { 1570 mNode.mFlags = (mNode.mFlags & ~ViewNode.FLAGS_OPAQUE) 1571 | (opaque ? ViewNode.FLAGS_OPAQUE : 0); 1572 } 1573 1574 @Override setClassName(String className)1575 public void setClassName(String className) { 1576 mNode.mClassName = className; 1577 } 1578 1579 @Override setContentDescription(CharSequence contentDescription)1580 public void setContentDescription(CharSequence contentDescription) { 1581 mNode.mContentDescription = contentDescription; 1582 } 1583 getNodeText()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 setText(CharSequence text)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 setText(CharSequence text, int selectionStart, int selectionEnd)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 setTextStyle(float size, int fgColor, int bgColor, int style)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 setTextLines(int[] charOffsets, int[] baselines)1617 public void setTextLines(int[] charOffsets, int[] baselines) { 1618 ViewNodeText t = getNodeText(); 1619 t.mLineCharOffsets = charOffsets; 1620 t.mLineBaselines = baselines; 1621 } 1622 1623 @Override setHint(CharSequence hint)1624 public void setHint(CharSequence hint) { 1625 getNodeText().mHint = hint != null ? hint.toString() : null; 1626 } 1627 1628 @Override getText()1629 public CharSequence getText() { 1630 return mNode.mText != null ? mNode.mText.mText : null; 1631 } 1632 1633 @Override getTextSelectionStart()1634 public int getTextSelectionStart() { 1635 return mNode.mText != null ? mNode.mText.mTextSelectionStart : -1; 1636 } 1637 1638 @Override getTextSelectionEnd()1639 public int getTextSelectionEnd() { 1640 return mNode.mText != null ? mNode.mText.mTextSelectionEnd : -1; 1641 } 1642 1643 @Override getHint()1644 public CharSequence getHint() { 1645 return mNode.mText != null ? mNode.mText.mHint : null; 1646 } 1647 1648 @Override getExtras()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 hasExtras()1658 public boolean hasExtras() { 1659 return mNode.mExtras != null; 1660 } 1661 1662 @Override setChildCount(int num)1663 public void setChildCount(int num) { 1664 mNode.mChildren = new ViewNode[num]; 1665 } 1666 1667 @Override addChildCount(int num)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 getChildCount()1681 public int getChildCount() { 1682 return mNode.mChildren != null ? mNode.mChildren.length : 0; 1683 } 1684 1685 @Override newChild(int index)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 asyncNewChild(int index)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 asyncCommit()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 getTempRect()1718 public Rect getTempRect() { 1719 return mAssist.mTmpRect; 1720 } 1721 1722 @Override setAutofillId(@onNull AutofillId id)1723 public void setAutofillId(@NonNull AutofillId id) { 1724 mNode.mAutofillId = id; 1725 } 1726 1727 @Override setAutofillId(@onNull AutofillId parentId, int virtualId)1728 public void setAutofillId(@NonNull AutofillId parentId, int virtualId) { 1729 mNode.mAutofillId = new AutofillId(parentId, virtualId); 1730 } 1731 1732 @Override getAutofillId()1733 public AutofillId getAutofillId() { 1734 return mNode.mAutofillId; 1735 } 1736 1737 @Override setAutofillType(@iew.AutofillType int type)1738 public void setAutofillType(@View.AutofillType int type) { 1739 mNode.mAutofillType = type; 1740 } 1741 1742 @Override setAutofillHints(@ullable String[] hints)1743 public void setAutofillHints(@Nullable String[] hints) { 1744 mNode.mAutofillHints = hints; 1745 } 1746 1747 @Override setAutofillValue(AutofillValue value)1748 public void setAutofillValue(AutofillValue value) { 1749 mNode.mAutofillValue = value; 1750 } 1751 1752 @Override setAutofillOptions(CharSequence[] options)1753 public void setAutofillOptions(CharSequence[] options) { 1754 mNode.mAutofillOptions = options; 1755 } 1756 1757 @Override setInputType(int inputType)1758 public void setInputType(int inputType) { 1759 mNode.mInputType = inputType; 1760 } 1761 1762 @Override setDataIsSensitive(boolean sensitive)1763 public void setDataIsSensitive(boolean sensitive) { 1764 mNode.mSanitized = !sensitive; 1765 } 1766 1767 @Override setWebDomain(@ullable String domain)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 setLocaleList(LocaleList localeList)1777 public void setLocaleList(LocaleList localeList) { 1778 mNode.mLocaleList = localeList; 1779 } 1780 1781 @Override newHtmlInfoBuilder(@onNull String tagName)1782 public HtmlInfo.Builder newHtmlInfoBuilder(@NonNull String tagName) { 1783 return new HtmlInfoNodeBuilder(tagName); 1784 } 1785 1786 @Override setHtmlInfo(@onNull HtmlInfo htmlInfo)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 HtmlInfoNode(HtmlInfoNodeBuilder builder)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 getTag()1814 public String getTag() { 1815 return mTag; 1816 } 1817 1818 @Override getAttributes()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 describeContents()1831 public int describeContents() { 1832 return 0; 1833 } 1834 1835 @Override writeToParcel(Parcel parcel, int flags)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 HtmlInfoNodeBuilder(String tag)1878 HtmlInfoNodeBuilder(String tag) { 1879 mTag = tag; 1880 } 1881 1882 @Override addAttribute(String name, String value)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 build()1894 public HtmlInfoNode build() { 1895 return new HtmlInfoNode(this); 1896 } 1897 } 1898 1899 /** @hide */ AssistStructure(Activity activity, boolean forAutoFill, int flags)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 if (root.getView() == null) { 1909 Log.w(TAG, "Skipping window with dettached view: " + root.getTitle()); 1910 continue; 1911 } 1912 mWindowNodes.add(new WindowNode(this, root, forAutoFill, flags)); 1913 } 1914 } 1915 AssistStructure()1916 public AssistStructure() { 1917 mHaveData = true; 1918 mActivityComponent = null; 1919 mFlags = 0; 1920 } 1921 1922 /** @hide */ AssistStructure(Parcel in)1923 public AssistStructure(Parcel in) { 1924 mIsHomeActivity = in.readInt() == 1; 1925 mReceiveChannel = in.readStrongBinder(); 1926 } 1927 1928 /** 1929 * Helper method used to sanitize the structure before it's written to a parcel. 1930 * 1931 * <p>Used just on autofill. 1932 * @hide 1933 */ sanitizeForParceling(boolean sanitize)1934 public void sanitizeForParceling(boolean sanitize) { 1935 mSanitizeOnWrite = sanitize; 1936 } 1937 1938 /** @hide */ dump(boolean showSensitive)1939 public void dump(boolean showSensitive) { 1940 if (mActivityComponent == null) { 1941 Log.i(TAG, "dump(): calling ensureData() first"); 1942 ensureData(); 1943 } 1944 Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString()); 1945 Log.i(TAG, "Sanitize on write: " + mSanitizeOnWrite); 1946 Log.i(TAG, "Flags: " + mFlags); 1947 final int N = getWindowNodeCount(); 1948 for (int i=0; i<N; i++) { 1949 WindowNode node = getWindowNodeAt(i); 1950 Log.i(TAG, "Window #" + i + " [" + node.getLeft() + "," + node.getTop() 1951 + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getTitle()); 1952 dump(" ", node.getRootViewNode(), showSensitive); 1953 } 1954 } 1955 dump(String prefix, ViewNode node, boolean showSensitive)1956 void dump(String prefix, ViewNode node, boolean showSensitive) { 1957 Log.i(TAG, prefix + "View [" + node.getLeft() + "," + node.getTop() 1958 + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getClassName()); 1959 int id = node.getId(); 1960 if (id != 0) { 1961 StringBuilder sb = new StringBuilder(); 1962 sb.append(prefix); sb.append(" ID: #"); sb.append(Integer.toHexString(id)); 1963 String entry = node.getIdEntry(); 1964 if (entry != null) { 1965 String type = node.getIdType(); 1966 String pkg = node.getIdPackage(); 1967 sb.append(" "); sb.append(pkg); sb.append(":"); sb.append(type); 1968 sb.append("/"); sb.append(entry); 1969 } 1970 Log.i(TAG, sb.toString()); 1971 } 1972 int scrollX = node.getScrollX(); 1973 int scrollY = node.getScrollY(); 1974 if (scrollX != 0 || scrollY != 0) { 1975 Log.i(TAG, prefix + " Scroll: " + scrollX + "," + scrollY); 1976 } 1977 Matrix matrix = node.getTransformation(); 1978 if (matrix != null) { 1979 Log.i(TAG, prefix + " Transformation: " + matrix); 1980 } 1981 float elevation = node.getElevation(); 1982 if (elevation != 0) { 1983 Log.i(TAG, prefix + " Elevation: " + elevation); 1984 } 1985 float alpha = node.getAlpha(); 1986 if (alpha != 0) { 1987 Log.i(TAG, prefix + " Alpha: " + elevation); 1988 } 1989 CharSequence contentDescription = node.getContentDescription(); 1990 if (contentDescription != null) { 1991 Log.i(TAG, prefix + " Content description: " + contentDescription); 1992 } 1993 CharSequence text = node.getText(); 1994 if (text != null) { 1995 final String safeText = node.isSanitized() || showSensitive ? text.toString() 1996 : "REDACTED[" + text.length() + " chars]"; 1997 Log.i(TAG, prefix + " Text (sel " + node.getTextSelectionStart() + "-" 1998 + node.getTextSelectionEnd() + "): " + safeText); 1999 Log.i(TAG, prefix + " Text size: " + node.getTextSize() + " , style: #" 2000 + node.getTextStyle()); 2001 Log.i(TAG, prefix + " Text color fg: #" + Integer.toHexString(node.getTextColor()) 2002 + ", bg: #" + Integer.toHexString(node.getTextBackgroundColor())); 2003 Log.i(TAG, prefix + " Input type: " + node.getInputType()); 2004 } 2005 String webDomain = node.getWebDomain(); 2006 if (webDomain != null) { 2007 Log.i(TAG, prefix + " Web domain: " + webDomain); 2008 } 2009 HtmlInfo htmlInfo = node.getHtmlInfo(); 2010 if (htmlInfo != null) { 2011 Log.i(TAG, prefix + " HtmlInfo: tag=" + htmlInfo.getTag() 2012 + ", attr="+ htmlInfo.getAttributes()); 2013 } 2014 2015 LocaleList localeList = node.getLocaleList(); 2016 if (localeList != null) { 2017 Log.i(TAG, prefix + " LocaleList: " + localeList); 2018 } 2019 String hint = node.getHint(); 2020 if (hint != null) { 2021 Log.i(TAG, prefix + " Hint: " + hint); 2022 } 2023 Bundle extras = node.getExtras(); 2024 if (extras != null) { 2025 Log.i(TAG, prefix + " Extras: " + extras); 2026 } 2027 if (node.isAssistBlocked()) { 2028 Log.i(TAG, prefix + " BLOCKED"); 2029 } 2030 AutofillId autofillId = node.getAutofillId(); 2031 if (autofillId == null) { 2032 Log.i(TAG, prefix + " NO autofill ID"); 2033 } else { 2034 Log.i(TAG, prefix + "Autofill info: id= " + autofillId 2035 + ", type=" + node.getAutofillType() 2036 + ", options=" + Arrays.toString(node.getAutofillOptions()) 2037 + ", hints=" + Arrays.toString(node.getAutofillHints()) 2038 + ", value=" + node.getAutofillValue() 2039 + ", sanitized=" + node.isSanitized()); 2040 } 2041 2042 final int NCHILDREN = node.getChildCount(); 2043 if (NCHILDREN > 0) { 2044 Log.i(TAG, prefix + " Children:"); 2045 String cprefix = prefix + " "; 2046 for (int i=0; i<NCHILDREN; i++) { 2047 ViewNode cnode = node.getChildAt(i); 2048 dump(cprefix, cnode, showSensitive); 2049 } 2050 } 2051 } 2052 2053 /** 2054 * Return the activity this AssistStructure came from. 2055 */ getActivityComponent()2056 public ComponentName getActivityComponent() { 2057 ensureData(); 2058 return mActivityComponent; 2059 } 2060 2061 /** 2062 * Called by Autofill server when app forged a different value. 2063 * 2064 * @hide 2065 */ setActivityComponent(ComponentName componentName)2066 public void setActivityComponent(ComponentName componentName) { 2067 ensureData(); 2068 mActivityComponent = componentName; 2069 } 2070 2071 /** @hide */ getFlags()2072 public int getFlags() { 2073 return mFlags; 2074 } 2075 2076 /** 2077 * Returns whether the activity associated with this AssistStructure was the home activity 2078 * (Launcher) at the time the assist data was acquired. 2079 * @return Whether the activity was the home activity. 2080 * @see android.content.Intent#CATEGORY_HOME 2081 */ isHomeActivity()2082 public boolean isHomeActivity() { 2083 return mIsHomeActivity; 2084 } 2085 2086 /** 2087 * Return the number of window contents that have been collected in this assist data. 2088 */ getWindowNodeCount()2089 public int getWindowNodeCount() { 2090 ensureData(); 2091 return mWindowNodes.size(); 2092 } 2093 2094 /** 2095 * Return one of the windows in the assist data. 2096 * @param index Which window to retrieve, may be 0 to {@link #getWindowNodeCount()}-1. 2097 */ getWindowNodeAt(int index)2098 public WindowNode getWindowNodeAt(int index) { 2099 ensureData(); 2100 return mWindowNodes.get(index); 2101 } 2102 2103 /** @hide */ ensureData()2104 public void ensureData() { 2105 if (mHaveData) { 2106 return; 2107 } 2108 mHaveData = true; 2109 ParcelTransferReader reader = new ParcelTransferReader(mReceiveChannel); 2110 reader.go(); 2111 } 2112 waitForReady()2113 boolean waitForReady() { 2114 boolean skipStructure = false; 2115 synchronized (this) { 2116 long endTime = SystemClock.uptimeMillis() + 5000; 2117 long now; 2118 while (mPendingAsyncChildren.size() > 0 && (now=SystemClock.uptimeMillis()) < endTime) { 2119 try { 2120 wait(endTime-now); 2121 } catch (InterruptedException e) { 2122 } 2123 } 2124 if (mPendingAsyncChildren.size() > 0) { 2125 // We waited too long, assume none of the assist structure is valid. 2126 Log.w(TAG, "Skipping assist structure, waiting too long for async children (have " 2127 + mPendingAsyncChildren.size() + " remaining"); 2128 skipStructure = true; 2129 } 2130 } 2131 return !skipStructure; 2132 } 2133 2134 /** @hide */ clearSendChannel()2135 public void clearSendChannel() { 2136 if (mSendChannel != null) { 2137 mSendChannel.mAssistStructure = null; 2138 } 2139 } 2140 2141 @Override describeContents()2142 public int describeContents() { 2143 return 0; 2144 } 2145 2146 @Override writeToParcel(Parcel out, int flags)2147 public void writeToParcel(Parcel out, int flags) { 2148 out.writeInt(mIsHomeActivity ? 1 : 0); 2149 if (mHaveData) { 2150 // This object holds its data. We want to write a send channel that the 2151 // other side can use to retrieve that data. 2152 if (mSendChannel == null) { 2153 mSendChannel = new SendChannel(this); 2154 } 2155 out.writeStrongBinder(mSendChannel); 2156 } else { 2157 // This object doesn't hold its data, so just propagate along its receive channel. 2158 out.writeStrongBinder(mReceiveChannel); 2159 } 2160 } 2161 2162 public static final Parcelable.Creator<AssistStructure> CREATOR 2163 = new Parcelable.Creator<AssistStructure>() { 2164 @Override 2165 public AssistStructure createFromParcel(Parcel in) { 2166 return new AssistStructure(in); 2167 } 2168 2169 @Override 2170 public AssistStructure[] newArray(int size) { 2171 return new AssistStructure[size]; 2172 } 2173 }; 2174 } 2175