1 package android.app.assist; 2 3 import android.app.Activity; 4 import android.content.ComponentName; 5 import android.graphics.Matrix; 6 import android.graphics.Rect; 7 import android.os.BadParcelableException; 8 import android.os.Binder; 9 import android.os.Bundle; 10 import android.os.IBinder; 11 import android.os.Parcel; 12 import android.os.Parcelable; 13 import android.os.PooledStringReader; 14 import android.os.PooledStringWriter; 15 import android.os.RemoteException; 16 import android.os.SystemClock; 17 import android.text.TextUtils; 18 import android.util.Log; 19 import android.view.View; 20 import android.view.ViewStructure; 21 import android.view.ViewRootImpl; 22 import android.view.WindowManager; 23 import android.view.WindowManagerGlobal; 24 25 import java.util.ArrayList; 26 27 /** 28 * Assist data automatically created by the platform's implementation 29 * of {@link android.app.Activity#onProvideAssistData}. 30 */ 31 public class AssistStructure implements Parcelable { 32 static final String TAG = "AssistStructure"; 33 34 static final boolean DEBUG_PARCEL = false; 35 static final boolean DEBUG_PARCEL_CHILDREN = false; 36 static final boolean DEBUG_PARCEL_TREE = false; 37 38 static final int VALIDATE_WINDOW_TOKEN = 0x11111111; 39 static final int VALIDATE_VIEW_TOKEN = 0x22222222; 40 41 boolean mHaveData; 42 43 ComponentName mActivityComponent; 44 45 final ArrayList<WindowNode> mWindowNodes = new ArrayList<>(); 46 47 final ArrayList<ViewNodeBuilder> mPendingAsyncChildren = new ArrayList<>(); 48 49 SendChannel mSendChannel; 50 IBinder mReceiveChannel; 51 52 Rect mTmpRect = new Rect(); 53 54 static final int TRANSACTION_XFER = Binder.FIRST_CALL_TRANSACTION+1; 55 static final String DESCRIPTOR = "android.app.AssistStructure"; 56 57 final static class SendChannel extends Binder { 58 volatile AssistStructure mAssistStructure; 59 SendChannel(AssistStructure as)60 SendChannel(AssistStructure as) { 61 mAssistStructure = as; 62 } 63 onTransact(int code, Parcel data, Parcel reply, int flags)64 @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) 65 throws RemoteException { 66 if (code == TRANSACTION_XFER) { 67 AssistStructure as = mAssistStructure; 68 if (as == null) { 69 return true; 70 } 71 72 data.enforceInterface(DESCRIPTOR); 73 IBinder token = data.readStrongBinder(); 74 if (DEBUG_PARCEL) Log.d(TAG, "Request for data on " + as 75 + " using token " + token); 76 if (token != null) { 77 if (DEBUG_PARCEL) Log.d(TAG, "Resuming partial write of " + token); 78 if (token instanceof ParcelTransferWriter) { 79 ParcelTransferWriter xfer = (ParcelTransferWriter)token; 80 xfer.writeToParcel(as, reply); 81 return true; 82 } 83 Log.w(TAG, "Caller supplied bad token type: " + token); 84 // Don't write anything; this is the end of the data. 85 return true; 86 } 87 //long start = SystemClock.uptimeMillis(); 88 ParcelTransferWriter xfer = new ParcelTransferWriter(as, reply); 89 xfer.writeToParcel(as, reply); 90 //Log.i(TAG, "Time to parcel: " + (SystemClock.uptimeMillis()-start) + "ms"); 91 return true; 92 } else { 93 return super.onTransact(code, data, reply, flags); 94 } 95 } 96 } 97 98 final static class ViewStackEntry { 99 ViewNode node; 100 int curChild; 101 int numChildren; 102 } 103 104 final static class ParcelTransferWriter extends Binder { 105 final boolean mWriteStructure; 106 int mCurWindow; 107 int mNumWindows; 108 final ArrayList<ViewStackEntry> mViewStack = new ArrayList<>(); 109 ViewStackEntry mCurViewStackEntry; 110 int mCurViewStackPos; 111 int mNumWrittenWindows; 112 int mNumWrittenViews; 113 final float[] mTmpMatrix = new float[9]; 114 ParcelTransferWriter(AssistStructure as, Parcel out)115 ParcelTransferWriter(AssistStructure as, Parcel out) { 116 mWriteStructure = as.waitForReady(); 117 ComponentName.writeToParcel(as.mActivityComponent, out); 118 mNumWindows = as.mWindowNodes.size(); 119 if (mWriteStructure && mNumWindows > 0) { 120 out.writeInt(mNumWindows); 121 } else { 122 out.writeInt(0); 123 } 124 } 125 writeToParcel(AssistStructure as, Parcel out)126 void writeToParcel(AssistStructure as, Parcel out) { 127 int start = out.dataPosition(); 128 mNumWrittenWindows = 0; 129 mNumWrittenViews = 0; 130 boolean more = writeToParcelInner(as, out); 131 Log.i(TAG, "Flattened " + (more ? "partial" : "final") + " assist data: " 132 + (out.dataPosition() - start) 133 + " bytes, containing " + mNumWrittenWindows + " windows, " 134 + mNumWrittenViews + " views"); 135 } 136 writeToParcelInner(AssistStructure as, Parcel out)137 boolean writeToParcelInner(AssistStructure as, Parcel out) { 138 if (mNumWindows == 0) { 139 return false; 140 } 141 if (DEBUG_PARCEL) Log.d(TAG, "Creating PooledStringWriter @ " + out.dataPosition()); 142 PooledStringWriter pwriter = new PooledStringWriter(out); 143 while (writeNextEntryToParcel(as, out, pwriter)) { 144 // If the parcel is above the IPC limit, then we are getting too 145 // large for a single IPC so stop here and let the caller come back when it 146 // is ready for more. 147 if (out.dataSize() > IBinder.MAX_IPC_SIZE) { 148 if (DEBUG_PARCEL) Log.d(TAG, "Assist data size is " + out.dataSize() 149 + " @ pos " + out.dataPosition() + "; returning partial result"); 150 out.writeInt(0); 151 out.writeStrongBinder(this); 152 if (DEBUG_PARCEL) Log.d(TAG, "Finishing PooledStringWriter @ " 153 + out.dataPosition() + ", size " + pwriter.getStringCount()); 154 pwriter.finish(); 155 return true; 156 } 157 } 158 if (DEBUG_PARCEL) Log.d(TAG, "Finishing PooledStringWriter @ " 159 + out.dataPosition() + ", size " + pwriter.getStringCount()); 160 pwriter.finish(); 161 mViewStack.clear(); 162 return false; 163 } 164 pushViewStackEntry(ViewNode node, int pos)165 void pushViewStackEntry(ViewNode node, int pos) { 166 ViewStackEntry entry; 167 if (pos >= mViewStack.size()) { 168 entry = new ViewStackEntry(); 169 mViewStack.add(entry); 170 if (DEBUG_PARCEL_TREE) Log.d(TAG, "New stack entry at " + pos + ": " + entry); 171 } else { 172 entry = mViewStack.get(pos); 173 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Existing stack entry at " + pos + ": " + entry); 174 } 175 entry.node = node; 176 entry.numChildren = node.getChildCount(); 177 entry.curChild = 0; 178 mCurViewStackEntry = entry; 179 } 180 writeView(ViewNode child, Parcel out, PooledStringWriter pwriter, int levelAdj)181 void writeView(ViewNode child, Parcel out, PooledStringWriter pwriter, int levelAdj) { 182 if (DEBUG_PARCEL) Log.d(TAG, "write view: at " + out.dataPosition() 183 + ", windows=" + mNumWrittenWindows 184 + ", views=" + mNumWrittenViews 185 + ", level=" + (mCurViewStackPos+levelAdj)); 186 out.writeInt(VALIDATE_VIEW_TOKEN); 187 int flags = child.writeSelfToParcel(out, pwriter, mTmpMatrix); 188 mNumWrittenViews++; 189 // If the child has children, push it on the stack to write them next. 190 if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) { 191 if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG, 192 "Preparing to write " + child.mChildren.length 193 + " children: @ #" + mNumWrittenViews 194 + ", level " + (mCurViewStackPos+levelAdj)); 195 out.writeInt(child.mChildren.length); 196 int pos = ++mCurViewStackPos; 197 pushViewStackEntry(child, pos); 198 } 199 } 200 writeNextEntryToParcel(AssistStructure as, Parcel out, PooledStringWriter pwriter)201 boolean writeNextEntryToParcel(AssistStructure as, Parcel out, PooledStringWriter pwriter) { 202 // Write next view node if appropriate. 203 if (mCurViewStackEntry != null) { 204 if (mCurViewStackEntry.curChild < mCurViewStackEntry.numChildren) { 205 // Write the next child in the current view. 206 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Writing child #" 207 + mCurViewStackEntry.curChild + " in " + mCurViewStackEntry.node); 208 ViewNode child = mCurViewStackEntry.node.mChildren[mCurViewStackEntry.curChild]; 209 mCurViewStackEntry.curChild++; 210 writeView(child, out, pwriter, 1); 211 return true; 212 } 213 214 // We are done writing children of the current view; pop off the stack. 215 do { 216 int pos = --mCurViewStackPos; 217 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Done with " + mCurViewStackEntry.node 218 + "; popping up to " + pos); 219 if (pos < 0) { 220 // Reached the last view; step to next window. 221 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Done with view hierarchy!"); 222 mCurViewStackEntry = null; 223 break; 224 } 225 mCurViewStackEntry = mViewStack.get(pos); 226 } while (mCurViewStackEntry.curChild >= mCurViewStackEntry.numChildren); 227 return true; 228 } 229 230 // Write the next window if appropriate. 231 int pos = mCurWindow; 232 if (pos < mNumWindows) { 233 WindowNode win = as.mWindowNodes.get(pos); 234 mCurWindow++; 235 if (DEBUG_PARCEL) Log.d(TAG, "write window #" + pos + ": at " + out.dataPosition() 236 + ", windows=" + mNumWrittenWindows 237 + ", views=" + mNumWrittenViews); 238 out.writeInt(VALIDATE_WINDOW_TOKEN); 239 win.writeSelfToParcel(out, pwriter, mTmpMatrix); 240 mNumWrittenWindows++; 241 ViewNode root = win.mRoot; 242 mCurViewStackPos = 0; 243 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Writing initial root view " + root); 244 writeView(root, out, pwriter, 0); 245 return true; 246 } 247 248 return false; 249 } 250 } 251 252 final class ParcelTransferReader { 253 final float[] mTmpMatrix = new float[9]; 254 PooledStringReader mStringReader; 255 256 int mNumReadWindows; 257 int mNumReadViews; 258 259 private final IBinder mChannel; 260 private IBinder mTransferToken; 261 private Parcel mCurParcel; 262 ParcelTransferReader(IBinder channel)263 ParcelTransferReader(IBinder channel) { 264 mChannel = channel; 265 } 266 go()267 void go() { 268 fetchData(); 269 mActivityComponent = ComponentName.readFromParcel(mCurParcel); 270 final int N = mCurParcel.readInt(); 271 if (N > 0) { 272 if (DEBUG_PARCEL) Log.d(TAG, "Creating PooledStringReader @ " 273 + mCurParcel.dataPosition()); 274 mStringReader = new PooledStringReader(mCurParcel); 275 if (DEBUG_PARCEL) Log.d(TAG, "PooledStringReader size = " 276 + mStringReader.getStringCount()); 277 for (int i=0; i<N; i++) { 278 mWindowNodes.add(new WindowNode(this)); 279 } 280 } 281 if (DEBUG_PARCEL) Log.d(TAG, "Finished reading: at " + mCurParcel.dataPosition() 282 + ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows 283 + ", views=" + mNumReadViews); 284 } 285 readParcel(int validateToken, int level)286 Parcel readParcel(int validateToken, int level) { 287 if (DEBUG_PARCEL) Log.d(TAG, "readParcel: at " + mCurParcel.dataPosition() 288 + ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows 289 + ", views=" + mNumReadViews + ", level=" + level); 290 int token = mCurParcel.readInt(); 291 if (token != 0) { 292 if (token != validateToken) { 293 throw new BadParcelableException("Got token " + Integer.toHexString(token) 294 + ", expected token " + Integer.toHexString(validateToken)); 295 } 296 return mCurParcel; 297 } 298 // We have run out of partial data, need to read another batch. 299 mTransferToken = mCurParcel.readStrongBinder(); 300 if (mTransferToken == null) { 301 throw new IllegalStateException( 302 "Reached end of partial data without transfer token"); 303 } 304 if (DEBUG_PARCEL) Log.d(TAG, "Ran out of partial data at " 305 + mCurParcel.dataPosition() + ", token " + mTransferToken); 306 fetchData(); 307 if (DEBUG_PARCEL) Log.d(TAG, "Creating PooledStringReader @ " 308 + mCurParcel.dataPosition()); 309 mStringReader = new PooledStringReader(mCurParcel); 310 if (DEBUG_PARCEL) Log.d(TAG, "PooledStringReader size = " 311 + mStringReader.getStringCount()); 312 if (DEBUG_PARCEL) Log.d(TAG, "readParcel: at " + mCurParcel.dataPosition() 313 + ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows 314 + ", views=" + mNumReadViews); 315 mCurParcel.readInt(); 316 return mCurParcel; 317 } 318 fetchData()319 private void fetchData() { 320 Parcel data = Parcel.obtain(); 321 data.writeInterfaceToken(DESCRIPTOR); 322 data.writeStrongBinder(mTransferToken); 323 if (DEBUG_PARCEL) Log.d(TAG, "Requesting data with token " + mTransferToken); 324 if (mCurParcel != null) { 325 mCurParcel.recycle(); 326 } 327 mCurParcel = Parcel.obtain(); 328 try { 329 mChannel.transact(TRANSACTION_XFER, data, mCurParcel, 0); 330 } catch (RemoteException e) { 331 Log.w(TAG, "Failure reading AssistStructure data", e); 332 throw new IllegalStateException("Failure reading AssistStructure data: " + e); 333 } 334 data.recycle(); 335 mNumReadWindows = mNumReadViews = 0; 336 } 337 } 338 339 final static class ViewNodeText { 340 CharSequence mText; 341 float mTextSize; 342 int mTextStyle; 343 int mTextColor = ViewNode.TEXT_COLOR_UNDEFINED; 344 int mTextBackgroundColor = ViewNode.TEXT_COLOR_UNDEFINED; 345 int mTextSelectionStart; 346 int mTextSelectionEnd; 347 int[] mLineCharOffsets; 348 int[] mLineBaselines; 349 String mHint; 350 ViewNodeText()351 ViewNodeText() { 352 } 353 isSimple()354 boolean isSimple() { 355 return mTextBackgroundColor == ViewNode.TEXT_COLOR_UNDEFINED 356 && mTextSelectionStart == 0 && mTextSelectionEnd == 0 357 && mLineCharOffsets == null && mLineBaselines == null && mHint == null; 358 } 359 ViewNodeText(Parcel in, boolean simple)360 ViewNodeText(Parcel in, boolean simple) { 361 mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 362 mTextSize = in.readFloat(); 363 mTextStyle = in.readInt(); 364 mTextColor = in.readInt(); 365 if (!simple) { 366 mTextBackgroundColor = in.readInt(); 367 mTextSelectionStart = in.readInt(); 368 mTextSelectionEnd = in.readInt(); 369 mLineCharOffsets = in.createIntArray(); 370 mLineBaselines = in.createIntArray(); 371 mHint = in.readString(); 372 } 373 } 374 writeToParcel(Parcel out, boolean simple)375 void writeToParcel(Parcel out, boolean simple) { 376 TextUtils.writeToParcel(mText, out, 0); 377 out.writeFloat(mTextSize); 378 out.writeInt(mTextStyle); 379 out.writeInt(mTextColor); 380 if (!simple) { 381 out.writeInt(mTextBackgroundColor); 382 out.writeInt(mTextSelectionStart); 383 out.writeInt(mTextSelectionEnd); 384 out.writeIntArray(mLineCharOffsets); 385 out.writeIntArray(mLineBaselines); 386 out.writeString(mHint); 387 } 388 } 389 } 390 391 /** 392 * Describes a window in the assist data. 393 */ 394 static public class WindowNode { 395 final int mX; 396 final int mY; 397 final int mWidth; 398 final int mHeight; 399 final CharSequence mTitle; 400 final int mDisplayId; 401 final ViewNode mRoot; 402 WindowNode(AssistStructure assist, ViewRootImpl root)403 WindowNode(AssistStructure assist, ViewRootImpl root) { 404 View view = root.getView(); 405 Rect rect = new Rect(); 406 view.getBoundsOnScreen(rect); 407 mX = rect.left - view.getLeft(); 408 mY = rect.top - view.getTop(); 409 mWidth = rect.width(); 410 mHeight = rect.height(); 411 mTitle = root.getTitle(); 412 mDisplayId = root.getDisplayId(); 413 mRoot = new ViewNode(); 414 ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false); 415 if ((root.getWindowFlags()& WindowManager.LayoutParams.FLAG_SECURE) != 0) { 416 // This is a secure window, so it doesn't want a screenshot, and that 417 // means we should also not copy out its view hierarchy. 418 view.onProvideStructure(builder); 419 builder.setAssistBlocked(true); 420 return; 421 } 422 view.dispatchProvideStructure(builder); 423 } 424 WindowNode(ParcelTransferReader reader)425 WindowNode(ParcelTransferReader reader) { 426 Parcel in = reader.readParcel(VALIDATE_WINDOW_TOKEN, 0); 427 reader.mNumReadWindows++; 428 mX = in.readInt(); 429 mY = in.readInt(); 430 mWidth = in.readInt(); 431 mHeight = in.readInt(); 432 mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 433 mDisplayId = in.readInt(); 434 mRoot = new ViewNode(reader, 0); 435 } 436 writeSelfToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix)437 void writeSelfToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix) { 438 out.writeInt(mX); 439 out.writeInt(mY); 440 out.writeInt(mWidth); 441 out.writeInt(mHeight); 442 TextUtils.writeToParcel(mTitle, out, 0); 443 out.writeInt(mDisplayId); 444 } 445 446 /** 447 * Returns the left edge of the window, in pixels, relative to the left 448 * edge of the screen. 449 */ getLeft()450 public int getLeft() { 451 return mX; 452 } 453 454 /** 455 * Returns the top edge of the window, in pixels, relative to the top 456 * edge of the screen. 457 */ getTop()458 public int getTop() { 459 return mY; 460 } 461 462 /** 463 * Returns the total width of the window in pixels. 464 */ getWidth()465 public int getWidth() { 466 return mWidth; 467 } 468 469 /** 470 * Returns the total height of the window in pixels. 471 */ getHeight()472 public int getHeight() { 473 return mHeight; 474 } 475 476 /** 477 * Returns the title associated with the window, if it has one. 478 */ getTitle()479 public CharSequence getTitle() { 480 return mTitle; 481 } 482 483 /** 484 * Returns the ID of the display this window is on, for use with 485 * {@link android.hardware.display.DisplayManager#getDisplay DisplayManager.getDisplay()}. 486 */ getDisplayId()487 public int getDisplayId() { 488 return mDisplayId; 489 } 490 491 /** 492 * Returns the {@link ViewNode} containing the root content of the window. 493 */ getRootViewNode()494 public ViewNode getRootViewNode() { 495 return mRoot; 496 } 497 } 498 499 /** 500 * Describes a single view in the assist data. 501 */ 502 static public class ViewNode { 503 /** 504 * Magic value for text color that has not been defined, which is very unlikely 505 * to be confused with a real text color. 506 */ 507 public static final int TEXT_COLOR_UNDEFINED = 1; 508 509 public static final int TEXT_STYLE_BOLD = 1<<0; 510 public static final int TEXT_STYLE_ITALIC = 1<<1; 511 public static final int TEXT_STYLE_UNDERLINE = 1<<2; 512 public static final int TEXT_STYLE_STRIKE_THRU = 1<<3; 513 514 int mId = View.NO_ID; 515 String mIdPackage; 516 String mIdType; 517 String mIdEntry; 518 int mX; 519 int mY; 520 int mScrollX; 521 int mScrollY; 522 int mWidth; 523 int mHeight; 524 Matrix mMatrix; 525 float mElevation; 526 float mAlpha = 1.0f; 527 528 static final int FLAGS_DISABLED = 0x00000001; 529 static final int FLAGS_VISIBILITY_MASK = View.VISIBLE|View.INVISIBLE|View.GONE; 530 static final int FLAGS_FOCUSABLE = 0x00000010; 531 static final int FLAGS_FOCUSED = 0x00000020; 532 static final int FLAGS_SELECTED = 0x00000040; 533 static final int FLAGS_ASSIST_BLOCKED = 0x00000080; 534 static final int FLAGS_CHECKABLE = 0x00000100; 535 static final int FLAGS_CHECKED = 0x00000200; 536 static final int FLAGS_CLICKABLE = 0x00000400; 537 static final int FLAGS_LONG_CLICKABLE = 0x00000800; 538 static final int FLAGS_ACCESSIBILITY_FOCUSED = 0x00001000; 539 static final int FLAGS_ACTIVATED = 0x00002000; 540 static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000; 541 542 static final int FLAGS_HAS_MATRIX = 0x40000000; 543 static final int FLAGS_HAS_ALPHA = 0x20000000; 544 static final int FLAGS_HAS_ELEVATION = 0x10000000; 545 static final int FLAGS_HAS_SCROLL = 0x08000000; 546 static final int FLAGS_HAS_LARGE_COORDS = 0x04000000; 547 static final int FLAGS_HAS_CONTENT_DESCRIPTION = 0x02000000; 548 static final int FLAGS_HAS_TEXT = 0x01000000; 549 static final int FLAGS_HAS_COMPLEX_TEXT = 0x00800000; 550 static final int FLAGS_HAS_EXTRAS = 0x00400000; 551 static final int FLAGS_HAS_ID = 0x00200000; 552 static final int FLAGS_HAS_CHILDREN = 0x00100000; 553 static final int FLAGS_ALL_CONTROL = 0xfff00000; 554 555 int mFlags; 556 557 String mClassName; 558 CharSequence mContentDescription; 559 560 ViewNodeText mText; 561 Bundle mExtras; 562 563 ViewNode[] mChildren; 564 ViewNode()565 ViewNode() { 566 } 567 ViewNode(ParcelTransferReader reader, int nestingLevel)568 ViewNode(ParcelTransferReader reader, int nestingLevel) { 569 final Parcel in = reader.readParcel(VALIDATE_VIEW_TOKEN, nestingLevel); 570 reader.mNumReadViews++; 571 final PooledStringReader preader = reader.mStringReader; 572 mClassName = preader.readString(); 573 mFlags = in.readInt(); 574 final int flags = mFlags; 575 if ((flags&FLAGS_HAS_ID) != 0) { 576 mId = in.readInt(); 577 if (mId != 0) { 578 mIdEntry = preader.readString(); 579 if (mIdEntry != null) { 580 mIdType = preader.readString(); 581 mIdPackage = preader.readString(); 582 } 583 } 584 } 585 if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) { 586 mX = in.readInt(); 587 mY = in.readInt(); 588 mWidth = in.readInt(); 589 mHeight = in.readInt(); 590 } else { 591 int val = in.readInt(); 592 mX = val&0x7fff; 593 mY = (val>>16)&0x7fff; 594 val = in.readInt(); 595 mWidth = val&0x7fff; 596 mHeight = (val>>16)&0x7fff; 597 } 598 if ((flags&FLAGS_HAS_SCROLL) != 0) { 599 mScrollX = in.readInt(); 600 mScrollY = in.readInt(); 601 } 602 if ((flags&FLAGS_HAS_MATRIX) != 0) { 603 mMatrix = new Matrix(); 604 in.readFloatArray(reader.mTmpMatrix); 605 mMatrix.setValues(reader.mTmpMatrix); 606 } 607 if ((flags&FLAGS_HAS_ELEVATION) != 0) { 608 mElevation = in.readFloat(); 609 } 610 if ((flags&FLAGS_HAS_ALPHA) != 0) { 611 mAlpha = in.readFloat(); 612 } 613 if ((flags&FLAGS_HAS_CONTENT_DESCRIPTION) != 0) { 614 mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 615 } 616 if ((flags&FLAGS_HAS_TEXT) != 0) { 617 mText = new ViewNodeText(in, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0); 618 } 619 if ((flags&FLAGS_HAS_EXTRAS) != 0) { 620 mExtras = in.readBundle(); 621 } 622 if ((flags&FLAGS_HAS_CHILDREN) != 0) { 623 final int NCHILDREN = in.readInt(); 624 if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG, 625 "Preparing to read " + NCHILDREN 626 + " children: @ #" + reader.mNumReadViews 627 + ", level " + nestingLevel); 628 mChildren = new ViewNode[NCHILDREN]; 629 for (int i=0; i<NCHILDREN; i++) { 630 mChildren[i] = new ViewNode(reader, nestingLevel + 1); 631 } 632 } 633 } 634 writeSelfToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix)635 int writeSelfToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix) { 636 int flags = mFlags & ~FLAGS_ALL_CONTROL; 637 if (mId != View.NO_ID) { 638 flags |= FLAGS_HAS_ID; 639 } 640 if ((mX&~0x7fff) != 0 || (mY&~0x7fff) != 0 641 || (mWidth&~0x7fff) != 0 | (mHeight&~0x7fff) != 0) { 642 flags |= FLAGS_HAS_LARGE_COORDS; 643 } 644 if (mScrollX != 0 || mScrollY != 0) { 645 flags |= FLAGS_HAS_SCROLL; 646 } 647 if (mMatrix != null) { 648 flags |= FLAGS_HAS_MATRIX; 649 } 650 if (mElevation != 0) { 651 flags |= FLAGS_HAS_ELEVATION; 652 } 653 if (mAlpha != 1.0f) { 654 flags |= FLAGS_HAS_ALPHA; 655 } 656 if (mContentDescription != null) { 657 flags |= FLAGS_HAS_CONTENT_DESCRIPTION; 658 } 659 if (mText != null) { 660 flags |= FLAGS_HAS_TEXT; 661 if (!mText.isSimple()) { 662 flags |= FLAGS_HAS_COMPLEX_TEXT; 663 } 664 } 665 if (mExtras != null) { 666 flags |= FLAGS_HAS_EXTRAS; 667 } 668 if (mChildren != null) { 669 flags |= FLAGS_HAS_CHILDREN; 670 } 671 672 pwriter.writeString(mClassName); 673 out.writeInt(flags); 674 if ((flags&FLAGS_HAS_ID) != 0) { 675 out.writeInt(mId); 676 if (mId != 0) { 677 pwriter.writeString(mIdEntry); 678 if (mIdEntry != null) { 679 pwriter.writeString(mIdType); 680 pwriter.writeString(mIdPackage); 681 } 682 } 683 } 684 if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) { 685 out.writeInt(mX); 686 out.writeInt(mY); 687 out.writeInt(mWidth); 688 out.writeInt(mHeight); 689 } else { 690 out.writeInt((mY<<16) | mX); 691 out.writeInt((mHeight<<16) | mWidth); 692 } 693 if ((flags&FLAGS_HAS_SCROLL) != 0) { 694 out.writeInt(mScrollX); 695 out.writeInt(mScrollY); 696 } 697 if ((flags&FLAGS_HAS_MATRIX) != 0) { 698 mMatrix.getValues(tmpMatrix); 699 out.writeFloatArray(tmpMatrix); 700 } 701 if ((flags&FLAGS_HAS_ELEVATION) != 0) { 702 out.writeFloat(mElevation); 703 } 704 if ((flags&FLAGS_HAS_ALPHA) != 0) { 705 out.writeFloat(mAlpha); 706 } 707 if ((flags&FLAGS_HAS_CONTENT_DESCRIPTION) != 0) { 708 TextUtils.writeToParcel(mContentDescription, out, 0); 709 } 710 if ((flags&FLAGS_HAS_TEXT) != 0) { 711 mText.writeToParcel(out, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0); 712 } 713 if ((flags&FLAGS_HAS_EXTRAS) != 0) { 714 out.writeBundle(mExtras); 715 } 716 return flags; 717 } 718 719 /** 720 * Returns the ID associated with this view, as per {@link View#getId() View.getId()}. 721 */ getId()722 public int getId() { 723 return mId; 724 } 725 726 /** 727 * If {@link #getId()} is a resource identifier, this is the package name of that 728 * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId} 729 * for more information. 730 */ getIdPackage()731 public String getIdPackage() { 732 return mIdPackage; 733 } 734 735 /** 736 * If {@link #getId()} is a resource identifier, this is the type name of that 737 * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId} 738 * for more information. 739 */ getIdType()740 public String getIdType() { 741 return mIdType; 742 } 743 744 /** 745 * If {@link #getId()} is a resource identifier, this is the entry name of that 746 * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId} 747 * for more information. 748 */ getIdEntry()749 public String getIdEntry() { 750 return mIdEntry; 751 } 752 753 /** 754 * Returns the left edge of this view, in pixels, relative to the left edge of its parent. 755 */ getLeft()756 public int getLeft() { 757 return mX; 758 } 759 760 /** 761 * Returns the top edge of this view, in pixels, relative to the top edge of its parent. 762 */ getTop()763 public int getTop() { 764 return mY; 765 } 766 767 /** 768 * Returns the current X scroll offset of this view, as per 769 * {@link android.view.View#getScrollX() View.getScrollX()}. 770 */ getScrollX()771 public int getScrollX() { 772 return mScrollX; 773 } 774 775 /** 776 * Returns the current Y scroll offset of this view, as per 777 * {@link android.view.View#getScrollX() View.getScrollY()}. 778 */ getScrollY()779 public int getScrollY() { 780 return mScrollY; 781 } 782 783 /** 784 * Returns the width of this view, in pixels. 785 */ getWidth()786 public int getWidth() { 787 return mWidth; 788 } 789 790 /** 791 * Returns the height of this view, in pixels. 792 */ getHeight()793 public int getHeight() { 794 return mHeight; 795 } 796 797 /** 798 * Returns the transformation that has been applied to this view, such as a translation 799 * or scaling. The returned Matrix object is owned by ViewNode; do not modify it. 800 * Returns null if there is no transformation applied to the view. 801 */ getTransformation()802 public Matrix getTransformation() { 803 return mMatrix; 804 } 805 806 /** 807 * Returns the visual elevation of the view, used for shadowing and other visual 808 * characterstics, as set by {@link ViewStructure#setElevation 809 * ViewStructure.setElevation(float)}. 810 */ getElevation()811 public float getElevation() { 812 return mElevation; 813 } 814 815 /** 816 * Returns the alpha transformation of the view, used to reduce the overall opacity 817 * of the view's contents, as set by {@link ViewStructure#setAlpha 818 * ViewStructure.setAlpha(float)}. 819 */ getAlpha()820 public float getAlpha() { 821 return mAlpha; 822 } 823 824 /** 825 * Returns the visibility mode of this view, as per 826 * {@link android.view.View#getVisibility() View.getVisibility()}. 827 */ getVisibility()828 public int getVisibility() { 829 return mFlags&ViewNode.FLAGS_VISIBILITY_MASK; 830 } 831 832 /** 833 * Returns true if assist data has been blocked starting at this node in the hierarchy. 834 */ isAssistBlocked()835 public boolean isAssistBlocked() { 836 return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) != 0; 837 } 838 839 /** 840 * Returns true if this node is in an enabled state. 841 */ isEnabled()842 public boolean isEnabled() { 843 return (mFlags&ViewNode.FLAGS_DISABLED) == 0; 844 } 845 846 /** 847 * Returns true if this node is clickable by the user. 848 */ isClickable()849 public boolean isClickable() { 850 return (mFlags&ViewNode.FLAGS_CLICKABLE) != 0; 851 } 852 853 /** 854 * Returns true if this node can take input focus. 855 */ isFocusable()856 public boolean isFocusable() { 857 return (mFlags&ViewNode.FLAGS_FOCUSABLE) != 0; 858 } 859 860 /** 861 * Returns true if this node currently had input focus at the time that the 862 * structure was collected. 863 */ isFocused()864 public boolean isFocused() { 865 return (mFlags&ViewNode.FLAGS_FOCUSED) != 0; 866 } 867 868 /** 869 * Returns true if this node currently had accessibility focus at the time that the 870 * structure was collected. 871 */ isAccessibilityFocused()872 public boolean isAccessibilityFocused() { 873 return (mFlags&ViewNode.FLAGS_ACCESSIBILITY_FOCUSED) != 0; 874 } 875 876 /** 877 * Returns true if this node represents something that is checkable by the user. 878 */ isCheckable()879 public boolean isCheckable() { 880 return (mFlags&ViewNode.FLAGS_CHECKABLE) != 0; 881 } 882 883 /** 884 * Returns true if this node is currently in a checked state. 885 */ isChecked()886 public boolean isChecked() { 887 return (mFlags&ViewNode.FLAGS_CHECKED) != 0; 888 } 889 890 /** 891 * Returns true if this node has currently been selected by the user. 892 */ isSelected()893 public boolean isSelected() { 894 return (mFlags&ViewNode.FLAGS_SELECTED) != 0; 895 } 896 897 /** 898 * Returns true if this node has currently been activated by the user. 899 */ isActivated()900 public boolean isActivated() { 901 return (mFlags&ViewNode.FLAGS_ACTIVATED) != 0; 902 } 903 904 /** 905 * Returns true if this node is something the user can perform a long click/press on. 906 */ isLongClickable()907 public boolean isLongClickable() { 908 return (mFlags&ViewNode.FLAGS_LONG_CLICKABLE) != 0; 909 } 910 911 /** 912 * Returns true if this node is something the user can perform a context click on. 913 */ isContextClickable()914 public boolean isContextClickable() { 915 return (mFlags&ViewNode.FLAGS_CONTEXT_CLICKABLE) != 0; 916 } 917 918 /** 919 * Returns the class name of the node's implementation, indicating its behavior. 920 * For example, a button will report "android.widget.Button" meaning it behaves 921 * like a {@link android.widget.Button}. 922 */ getClassName()923 public String getClassName() { 924 return mClassName; 925 } 926 927 /** 928 * Returns any content description associated with the node, which semantically describes 929 * its purpose for accessibility and other uses. 930 */ getContentDescription()931 public CharSequence getContentDescription() { 932 return mContentDescription; 933 } 934 935 /** 936 * Returns any text associated with the node that is displayed to the user, or null 937 * if there is none. 938 */ getText()939 public CharSequence getText() { 940 return mText != null ? mText.mText : null; 941 } 942 943 /** 944 * If {@link #getText()} is non-null, this is where the current selection starts. 945 */ getTextSelectionStart()946 public int getTextSelectionStart() { 947 return mText != null ? mText.mTextSelectionStart : -1; 948 } 949 950 /** 951 * If {@link #getText()} is non-null, this is where the current selection starts. 952 * If there is no selection, returns the same value as {@link #getTextSelectionStart()}, 953 * indicating the cursor position. 954 */ getTextSelectionEnd()955 public int getTextSelectionEnd() { 956 return mText != null ? mText.mTextSelectionEnd : -1; 957 } 958 959 /** 960 * If {@link #getText()} is non-null, this is the main text color associated with it. 961 * If there is no text color, {@link #TEXT_COLOR_UNDEFINED} is returned. 962 * Note that the text may also contain style spans that modify the color of specific 963 * parts of the text. 964 */ getTextColor()965 public int getTextColor() { 966 return mText != null ? mText.mTextColor : TEXT_COLOR_UNDEFINED; 967 } 968 969 /** 970 * If {@link #getText()} is non-null, this is the main text background color associated 971 * with it. 972 * If there is no text background color, {@link #TEXT_COLOR_UNDEFINED} is returned. 973 * Note that the text may also contain style spans that modify the color of specific 974 * parts of the text. 975 */ getTextBackgroundColor()976 public int getTextBackgroundColor() { 977 return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED; 978 } 979 980 /** 981 * If {@link #getText()} is non-null, this is the main text size (in pixels) associated 982 * with it. 983 * Note that the text may also contain style spans that modify the size of specific 984 * parts of the text. 985 */ getTextSize()986 public float getTextSize() { 987 return mText != null ? mText.mTextSize : 0; 988 } 989 990 /** 991 * If {@link #getText()} is non-null, this is the main text style associated 992 * with it, containing a bit mask of {@link #TEXT_STYLE_BOLD}, 993 * {@link #TEXT_STYLE_BOLD}, {@link #TEXT_STYLE_STRIKE_THRU}, and/or 994 * {@link #TEXT_STYLE_UNDERLINE}. 995 * Note that the text may also contain style spans that modify the style of specific 996 * parts of the text. 997 */ getTextStyle()998 public int getTextStyle() { 999 return mText != null ? mText.mTextStyle : 0; 1000 } 1001 1002 /** 1003 * Return per-line offsets into the text returned by {@link #getText()}. Each entry 1004 * in the array is a formatted line of text, and the value it contains is the offset 1005 * into the text string where that line starts. May return null if there is no line 1006 * information. 1007 */ getTextLineCharOffsets()1008 public int[] getTextLineCharOffsets() { 1009 return mText != null ? mText.mLineCharOffsets : null; 1010 } 1011 1012 /** 1013 * Return per-line baselines into the text returned by {@link #getText()}. Each entry 1014 * in the array is a formatted line of text, and the value it contains is the baseline 1015 * where that text appears in the view. May return null if there is no line 1016 * information. 1017 */ getTextLineBaselines()1018 public int[] getTextLineBaselines() { 1019 return mText != null ? mText.mLineBaselines : null; 1020 } 1021 1022 /** 1023 * Return additional hint text associated with the node; this is typically used with 1024 * a node that takes user input, describing to the user what the input means. 1025 */ getHint()1026 public String getHint() { 1027 return mText != null ? mText.mHint : null; 1028 } 1029 1030 /** 1031 * Return a Bundle containing optional vendor-specific extension information. 1032 */ getExtras()1033 public Bundle getExtras() { 1034 return mExtras; 1035 } 1036 1037 /** 1038 * Return the number of children this node has. 1039 */ getChildCount()1040 public int getChildCount() { 1041 return mChildren != null ? mChildren.length : 0; 1042 } 1043 1044 /** 1045 * Return a child of this node, given an index value from 0 to 1046 * {@link #getChildCount()}-1. 1047 */ getChildAt(int index)1048 public ViewNode getChildAt(int index) { 1049 return mChildren[index]; 1050 } 1051 } 1052 1053 static class ViewNodeBuilder extends ViewStructure { 1054 final AssistStructure mAssist; 1055 final ViewNode mNode; 1056 final boolean mAsync; 1057 ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async)1058 ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async) { 1059 mAssist = assist; 1060 mNode = node; 1061 mAsync = async; 1062 } 1063 1064 @Override setId(int id, String packageName, String typeName, String entryName)1065 public void setId(int id, String packageName, String typeName, String entryName) { 1066 mNode.mId = id; 1067 mNode.mIdPackage = packageName; 1068 mNode.mIdType = typeName; 1069 mNode.mIdEntry = entryName; 1070 } 1071 1072 @Override setDimens(int left, int top, int scrollX, int scrollY, int width, int height)1073 public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) { 1074 mNode.mX = left; 1075 mNode.mY = top; 1076 mNode.mScrollX = scrollX; 1077 mNode.mScrollY = scrollY; 1078 mNode.mWidth = width; 1079 mNode.mHeight = height; 1080 } 1081 1082 @Override setTransformation(Matrix matrix)1083 public void setTransformation(Matrix matrix) { 1084 if (matrix == null) { 1085 mNode.mMatrix = null; 1086 } else { 1087 mNode.mMatrix = new Matrix(matrix); 1088 } 1089 } 1090 1091 @Override setElevation(float elevation)1092 public void setElevation(float elevation) { 1093 mNode.mElevation = elevation; 1094 } 1095 1096 @Override setAlpha(float alpha)1097 public void setAlpha(float alpha) { 1098 mNode.mAlpha = alpha; 1099 } 1100 1101 @Override setVisibility(int visibility)1102 public void setVisibility(int visibility) { 1103 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_VISIBILITY_MASK) | visibility; 1104 } 1105 1106 @Override setAssistBlocked(boolean state)1107 public void setAssistBlocked(boolean state) { 1108 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ASSIST_BLOCKED) 1109 | (state ? ViewNode.FLAGS_ASSIST_BLOCKED : 0); 1110 } 1111 1112 @Override setEnabled(boolean state)1113 public void setEnabled(boolean state) { 1114 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_DISABLED) 1115 | (state ? 0 : ViewNode.FLAGS_DISABLED); 1116 } 1117 1118 @Override setClickable(boolean state)1119 public void setClickable(boolean state) { 1120 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CLICKABLE) 1121 | (state ? ViewNode.FLAGS_CLICKABLE : 0); 1122 } 1123 1124 @Override setLongClickable(boolean state)1125 public void setLongClickable(boolean state) { 1126 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_LONG_CLICKABLE) 1127 | (state ? ViewNode.FLAGS_LONG_CLICKABLE : 0); 1128 } 1129 1130 @Override setContextClickable(boolean state)1131 public void setContextClickable(boolean state) { 1132 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CONTEXT_CLICKABLE) 1133 | (state ? ViewNode.FLAGS_CONTEXT_CLICKABLE : 0); 1134 } 1135 1136 @Override setFocusable(boolean state)1137 public void setFocusable(boolean state) { 1138 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSABLE) 1139 | (state ? ViewNode.FLAGS_FOCUSABLE : 0); 1140 } 1141 1142 @Override setFocused(boolean state)1143 public void setFocused(boolean state) { 1144 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSED) 1145 | (state ? ViewNode.FLAGS_FOCUSED : 0); 1146 } 1147 1148 @Override setAccessibilityFocused(boolean state)1149 public void setAccessibilityFocused(boolean state) { 1150 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACCESSIBILITY_FOCUSED) 1151 | (state ? ViewNode.FLAGS_ACCESSIBILITY_FOCUSED : 0); 1152 } 1153 1154 @Override setCheckable(boolean state)1155 public void setCheckable(boolean state) { 1156 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKABLE) 1157 | (state ? ViewNode.FLAGS_CHECKABLE : 0); 1158 } 1159 1160 @Override setChecked(boolean state)1161 public void setChecked(boolean state) { 1162 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKED) 1163 | (state ? ViewNode.FLAGS_CHECKED : 0); 1164 } 1165 1166 @Override setSelected(boolean state)1167 public void setSelected(boolean state) { 1168 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_SELECTED) 1169 | (state ? ViewNode.FLAGS_SELECTED : 0); 1170 } 1171 1172 @Override setActivated(boolean state)1173 public void setActivated(boolean state) { 1174 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACTIVATED) 1175 | (state ? ViewNode.FLAGS_ACTIVATED : 0); 1176 } 1177 1178 @Override setClassName(String className)1179 public void setClassName(String className) { 1180 mNode.mClassName = className; 1181 } 1182 1183 @Override setContentDescription(CharSequence contentDescription)1184 public void setContentDescription(CharSequence contentDescription) { 1185 mNode.mContentDescription = contentDescription; 1186 } 1187 getNodeText()1188 private final ViewNodeText getNodeText() { 1189 if (mNode.mText != null) { 1190 return mNode.mText; 1191 } 1192 mNode.mText = new ViewNodeText(); 1193 return mNode.mText; 1194 } 1195 1196 @Override setText(CharSequence text)1197 public void setText(CharSequence text) { 1198 ViewNodeText t = getNodeText(); 1199 t.mText = text; 1200 t.mTextSelectionStart = t.mTextSelectionEnd = -1; 1201 } 1202 1203 @Override setText(CharSequence text, int selectionStart, int selectionEnd)1204 public void setText(CharSequence text, int selectionStart, int selectionEnd) { 1205 ViewNodeText t = getNodeText(); 1206 t.mText = text; 1207 t.mTextSelectionStart = selectionStart; 1208 t.mTextSelectionEnd = selectionEnd; 1209 } 1210 1211 @Override setTextStyle(float size, int fgColor, int bgColor, int style)1212 public void setTextStyle(float size, int fgColor, int bgColor, int style) { 1213 ViewNodeText t = getNodeText(); 1214 t.mTextColor = fgColor; 1215 t.mTextBackgroundColor = bgColor; 1216 t.mTextSize = size; 1217 t.mTextStyle = style; 1218 } 1219 1220 @Override setTextLines(int[] charOffsets, int[] baselines)1221 public void setTextLines(int[] charOffsets, int[] baselines) { 1222 ViewNodeText t = getNodeText(); 1223 t.mLineCharOffsets = charOffsets; 1224 t.mLineBaselines = baselines; 1225 } 1226 1227 @Override setHint(CharSequence hint)1228 public void setHint(CharSequence hint) { 1229 getNodeText().mHint = hint != null ? hint.toString() : null; 1230 } 1231 1232 @Override getText()1233 public CharSequence getText() { 1234 return mNode.mText != null ? mNode.mText.mText : null; 1235 } 1236 1237 @Override getTextSelectionStart()1238 public int getTextSelectionStart() { 1239 return mNode.mText != null ? mNode.mText.mTextSelectionStart : -1; 1240 } 1241 1242 @Override getTextSelectionEnd()1243 public int getTextSelectionEnd() { 1244 return mNode.mText != null ? mNode.mText.mTextSelectionEnd : -1; 1245 } 1246 1247 @Override getHint()1248 public CharSequence getHint() { 1249 return mNode.mText != null ? mNode.mText.mHint : null; 1250 } 1251 1252 @Override getExtras()1253 public Bundle getExtras() { 1254 if (mNode.mExtras != null) { 1255 return mNode.mExtras; 1256 } 1257 mNode.mExtras = new Bundle(); 1258 return mNode.mExtras; 1259 } 1260 1261 @Override hasExtras()1262 public boolean hasExtras() { 1263 return mNode.mExtras != null; 1264 } 1265 1266 @Override setChildCount(int num)1267 public void setChildCount(int num) { 1268 mNode.mChildren = new ViewNode[num]; 1269 } 1270 1271 @Override addChildCount(int num)1272 public int addChildCount(int num) { 1273 if (mNode.mChildren == null) { 1274 setChildCount(num); 1275 return 0; 1276 } 1277 final int start = mNode.mChildren.length; 1278 ViewNode[] newArray = new ViewNode[start + num]; 1279 System.arraycopy(mNode.mChildren, 0, newArray, 0, start); 1280 mNode.mChildren = newArray; 1281 return start; 1282 } 1283 1284 @Override getChildCount()1285 public int getChildCount() { 1286 return mNode.mChildren != null ? mNode.mChildren.length : 0; 1287 } 1288 1289 @Override newChild(int index)1290 public ViewStructure newChild(int index) { 1291 ViewNode node = new ViewNode(); 1292 mNode.mChildren[index] = node; 1293 return new ViewNodeBuilder(mAssist, node, false); 1294 } 1295 1296 @Override asyncNewChild(int index)1297 public ViewStructure asyncNewChild(int index) { 1298 synchronized (mAssist) { 1299 ViewNode node = new ViewNode(); 1300 mNode.mChildren[index] = node; 1301 ViewNodeBuilder builder = new ViewNodeBuilder(mAssist, node, true); 1302 mAssist.mPendingAsyncChildren.add(builder); 1303 return builder; 1304 } 1305 } 1306 1307 @Override asyncCommit()1308 public void asyncCommit() { 1309 synchronized (mAssist) { 1310 if (!mAsync) { 1311 throw new IllegalStateException("Child " + this 1312 + " was not created with ViewStructure.asyncNewChild"); 1313 } 1314 if (!mAssist.mPendingAsyncChildren.remove(this)) { 1315 throw new IllegalStateException("Child " + this + " already committed"); 1316 } 1317 mAssist.notifyAll(); 1318 } 1319 } 1320 1321 @Override getTempRect()1322 public Rect getTempRect() { 1323 return mAssist.mTmpRect; 1324 } 1325 } 1326 1327 /** @hide */ AssistStructure(Activity activity)1328 public AssistStructure(Activity activity) { 1329 mHaveData = true; 1330 mActivityComponent = activity.getComponentName(); 1331 ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews( 1332 activity.getActivityToken()); 1333 for (int i=0; i<views.size(); i++) { 1334 ViewRootImpl root = views.get(i); 1335 mWindowNodes.add(new WindowNode(this, root)); 1336 } 1337 } 1338 AssistStructure()1339 public AssistStructure() { 1340 mHaveData = true; 1341 mActivityComponent = null; 1342 } 1343 1344 /** @hide */ AssistStructure(Parcel in)1345 public AssistStructure(Parcel in) { 1346 mReceiveChannel = in.readStrongBinder(); 1347 } 1348 1349 /** @hide */ dump()1350 public void dump() { 1351 Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString()); 1352 final int N = getWindowNodeCount(); 1353 for (int i=0; i<N; i++) { 1354 WindowNode node = getWindowNodeAt(i); 1355 Log.i(TAG, "Window #" + i + " [" + node.getLeft() + "," + node.getTop() 1356 + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getTitle()); 1357 dump(" ", node.getRootViewNode()); 1358 } 1359 } 1360 dump(String prefix, ViewNode node)1361 void dump(String prefix, ViewNode node) { 1362 Log.i(TAG, prefix + "View [" + node.getLeft() + "," + node.getTop() 1363 + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getClassName()); 1364 int id = node.getId(); 1365 if (id != 0) { 1366 StringBuilder sb = new StringBuilder(); 1367 sb.append(prefix); sb.append(" ID: #"); sb.append(Integer.toHexString(id)); 1368 String entry = node.getIdEntry(); 1369 if (entry != null) { 1370 String type = node.getIdType(); 1371 String pkg = node.getIdPackage(); 1372 sb.append(" "); sb.append(pkg); sb.append(":"); sb.append(type); 1373 sb.append("/"); sb.append(entry); 1374 } 1375 Log.i(TAG, sb.toString()); 1376 } 1377 int scrollX = node.getScrollX(); 1378 int scrollY = node.getScrollY(); 1379 if (scrollX != 0 || scrollY != 0) { 1380 Log.i(TAG, prefix + " Scroll: " + scrollX + "," + scrollY); 1381 } 1382 Matrix matrix = node.getTransformation(); 1383 if (matrix != null) { 1384 Log.i(TAG, prefix + " Transformation: " + matrix); 1385 } 1386 float elevation = node.getElevation(); 1387 if (elevation != 0) { 1388 Log.i(TAG, prefix + " Elevation: " + elevation); 1389 } 1390 float alpha = node.getAlpha(); 1391 if (alpha != 0) { 1392 Log.i(TAG, prefix + " Alpha: " + elevation); 1393 } 1394 CharSequence contentDescription = node.getContentDescription(); 1395 if (contentDescription != null) { 1396 Log.i(TAG, prefix + " Content description: " + contentDescription); 1397 } 1398 CharSequence text = node.getText(); 1399 if (text != null) { 1400 Log.i(TAG, prefix + " Text (sel " + node.getTextSelectionStart() + "-" 1401 + node.getTextSelectionEnd() + "): " + text); 1402 Log.i(TAG, prefix + " Text size: " + node.getTextSize() + " , style: #" 1403 + node.getTextStyle()); 1404 Log.i(TAG, prefix + " Text color fg: #" + Integer.toHexString(node.getTextColor()) 1405 + ", bg: #" + Integer.toHexString(node.getTextBackgroundColor())); 1406 } 1407 String hint = node.getHint(); 1408 if (hint != null) { 1409 Log.i(TAG, prefix + " Hint: " + hint); 1410 } 1411 Bundle extras = node.getExtras(); 1412 if (extras != null) { 1413 Log.i(TAG, prefix + " Extras: " + extras); 1414 } 1415 if (node.isAssistBlocked()) { 1416 Log.i(TAG, prefix + " BLOCKED"); 1417 } 1418 final int NCHILDREN = node.getChildCount(); 1419 if (NCHILDREN > 0) { 1420 Log.i(TAG, prefix + " Children:"); 1421 String cprefix = prefix + " "; 1422 for (int i=0; i<NCHILDREN; i++) { 1423 ViewNode cnode = node.getChildAt(i); 1424 dump(cprefix, cnode); 1425 } 1426 } 1427 } 1428 1429 /** 1430 * Return the activity this AssistStructure came from. 1431 */ getActivityComponent()1432 public ComponentName getActivityComponent() { 1433 ensureData(); 1434 return mActivityComponent; 1435 } 1436 1437 /** 1438 * Return the number of window contents that have been collected in this assist data. 1439 */ getWindowNodeCount()1440 public int getWindowNodeCount() { 1441 ensureData(); 1442 return mWindowNodes.size(); 1443 } 1444 1445 /** 1446 * Return one of the windows in the assist data. 1447 * @param index Which window to retrieve, may be 0 to {@link #getWindowNodeCount()}-1. 1448 */ getWindowNodeAt(int index)1449 public WindowNode getWindowNodeAt(int index) { 1450 ensureData(); 1451 return mWindowNodes.get(index); 1452 } 1453 1454 /** @hide */ ensureData()1455 public void ensureData() { 1456 if (mHaveData) { 1457 return; 1458 } 1459 mHaveData = true; 1460 ParcelTransferReader reader = new ParcelTransferReader(mReceiveChannel); 1461 reader.go(); 1462 } 1463 waitForReady()1464 boolean waitForReady() { 1465 boolean skipStructure = false; 1466 synchronized (this) { 1467 long endTime = SystemClock.uptimeMillis() + 5000; 1468 long now; 1469 while (mPendingAsyncChildren.size() > 0 && (now=SystemClock.uptimeMillis()) < endTime) { 1470 try { 1471 wait(endTime-now); 1472 } catch (InterruptedException e) { 1473 } 1474 } 1475 if (mPendingAsyncChildren.size() > 0) { 1476 // We waited too long, assume none of the assist structure is valid. 1477 Log.w(TAG, "Skipping assist structure, waiting too long for async children (have " 1478 + mPendingAsyncChildren.size() + " remaining"); 1479 skipStructure = true; 1480 } 1481 } 1482 return !skipStructure; 1483 } 1484 1485 /** @hide */ clearSendChannel()1486 public void clearSendChannel() { 1487 if (mSendChannel != null) { 1488 mSendChannel.mAssistStructure = null; 1489 } 1490 } 1491 describeContents()1492 public int describeContents() { 1493 return 0; 1494 } 1495 writeToParcel(Parcel out, int flags)1496 public void writeToParcel(Parcel out, int flags) { 1497 if (mHaveData) { 1498 // This object holds its data. We want to write a send channel that the 1499 // other side can use to retrieve that data. 1500 if (mSendChannel == null) { 1501 mSendChannel = new SendChannel(this); 1502 } 1503 out.writeStrongBinder(mSendChannel); 1504 } else { 1505 // This object doesn't hold its data, so just propagate along its receive channel. 1506 out.writeStrongBinder(mReceiveChannel); 1507 } 1508 } 1509 1510 public static final Parcelable.Creator<AssistStructure> CREATOR 1511 = new Parcelable.Creator<AssistStructure>() { 1512 public AssistStructure createFromParcel(Parcel in) { 1513 return new AssistStructure(in); 1514 } 1515 1516 public AssistStructure[] newArray(int size) { 1517 return new AssistStructure[size]; 1518 } 1519 }; 1520 } 1521