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