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