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