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