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