diff --git a/core/api/current.txt b/core/api/current.txt index 53273bf1cea70..359fe3e60f977 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -53885,6 +53885,7 @@ package android.view.accessibility { method public java.util.List getAvailableExtraData(); method @Deprecated public void getBoundsInParent(android.graphics.Rect); method public void getBoundsInScreen(android.graphics.Rect); + method public void getBoundsInWindow(@NonNull android.graphics.Rect); method public android.view.accessibility.AccessibilityNodeInfo getChild(int); method @Nullable public android.view.accessibility.AccessibilityNodeInfo getChild(int, int); method public int getChildCount(); @@ -53963,6 +53964,7 @@ package android.view.accessibility { method public void setAvailableExtraData(java.util.List); method @Deprecated public void setBoundsInParent(android.graphics.Rect); method public void setBoundsInScreen(android.graphics.Rect); + method public void setBoundsInWindow(@NonNull android.graphics.Rect); method public void setCanOpenPopup(boolean); method public void setCheckable(boolean); method public void setChecked(boolean); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 20f6baf3780f1..e4f246b82c3b7 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -8945,11 +8945,33 @@ public class View implements Drawable.Callback, KeyEvent.Callback, outRect.set(position.left, position.top, position.right, position.bottom); } + /** + * Gets the location of this view in window coordinates. + * + * @param outRect The output location + * @param clipToParent Whether to clip child bounds to the parent ones. + * @hide + */ + public void getBoundsInWindow(Rect outRect, boolean clipToParent) { + if (mAttachInfo == null) { + return; + } + RectF position = mAttachInfo.mTmpTransformRect; + getBoundsToWindowInternal(position, clipToParent); + outRect.set(Math.round(position.left), Math.round(position.top), + Math.round(position.right), Math.round(position.bottom)); + } + private void getBoundsToScreenInternal(RectF position, boolean clipToParent) { position.set(0, 0, mRight - mLeft, mBottom - mTop); mapRectFromViewToScreenCoords(position, clipToParent); } + private void getBoundsToWindowInternal(RectF position, boolean clipToParent) { + position.set(0, 0, mRight - mLeft, mBottom - mTop); + mapRectFromViewToWindowCoords(position, clipToParent); + } + /** * Map a rectangle from view-relative coordinates to screen-relative coordinates * @@ -8958,6 +8980,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { + mapRectFromViewToWindowCoords(rect, clipToParent); + rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); + } + + /** + * Map a rectangle from view-relative coordinates to window-relative coordinates + * + * @param rect The rectangle to be mapped + * @param clipToParent Whether to clip child bounds to the parent ones. + * @hide + */ + public void mapRectFromViewToWindowCoords(RectF rect, boolean clipToParent) { if (!hasIdentityMatrix()) { getMatrix().mapRect(rect); } @@ -8990,8 +9024,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, ViewRootImpl viewRootImpl = (ViewRootImpl) parent; rect.offset(0, -viewRootImpl.mCurScrollY); } - - rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); } /** @@ -10578,6 +10610,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, getBoundsOnScreen(bounds, true); info.setBoundsInScreen(bounds); + getBoundsInWindow(bounds, true); + info.setBoundsInWindow(bounds); ViewParent parent = getParentForAccessibility(); if (parent instanceof View) { diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index d88cdf1493e1c..4576d627dd611 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -906,6 +906,7 @@ public class AccessibilityNodeInfo implements Parcelable { private int mBooleanProperties; private final Rect mBoundsInParent = new Rect(); private final Rect mBoundsInScreen = new Rect(); + private final Rect mBoundsInWindow = new Rect(); private int mDrawingOrderInParent; private CharSequence mPackageName; @@ -2155,6 +2156,49 @@ public class AccessibilityNodeInfo implements Parcelable { mBoundsInScreen.set(bounds.left, bounds.top, bounds.right, bounds.bottom); } + /** + * Gets the node bounds in window coordinates. + *

+ * When magnification is enabled, the bounds in window are scaled up by magnification scale + * and the positions are also adjusted according to the offset of magnification viewport. + * For example, it returns Rect(-180, -180, 0, 0) for original bounds Rect(10, 10, 100, 100), + * when the magnification scale is 2 and offsets for X and Y are both 200. + *

+ * + * @param outBounds The output node bounds. + */ + public void getBoundsInWindow(@NonNull Rect outBounds) { + outBounds.set(mBoundsInWindow.left, mBoundsInWindow.top, + mBoundsInWindow.right, mBoundsInWindow.bottom); + } + + /** + * Returns the actual rect containing the node bounds in window coordinates. + * + * @hide Not safe to expose outside the framework. + */ + @NonNull + public Rect getBoundsInWindow() { + return mBoundsInWindow; + } + + /** + * Sets the node bounds in window coordinates. + *

+ * Note: Cannot be called from an + * {@link android.accessibilityservice.AccessibilityService}. + * This class is made immutable before being delivered to an AccessibilityService. + *

+ * + * @param bounds The node bounds. + * + * @throws IllegalStateException If called from an AccessibilityService. + */ + public void setBoundsInWindow(@NonNull Rect bounds) { + enforceNotSealed(); + mBoundsInWindow.set(bounds); + } + /** * Gets whether this node is checkable. * @@ -4054,6 +4098,11 @@ public class AccessibilityNodeInfo implements Parcelable { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; + if (!Objects.equals(mBoundsInWindow, DEFAULT.mBoundsInWindow)) { + nonDefaultFields |= bitAt(fieldIndex); + } + fieldIndex++; + if (!Objects.equals(mActions, DEFAULT.mActions)) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mMaxTextLength != DEFAULT.mMaxTextLength) nonDefaultFields |= bitAt(fieldIndex); @@ -4202,6 +4251,13 @@ public class AccessibilityNodeInfo implements Parcelable { parcel.writeInt(mBoundsInScreen.right); } + if (isBitSet(nonDefaultFields, fieldIndex++)) { + parcel.writeInt(mBoundsInWindow.top); + parcel.writeInt(mBoundsInWindow.bottom); + parcel.writeInt(mBoundsInWindow.left); + parcel.writeInt(mBoundsInWindow.right); + } + if (isBitSet(nonDefaultFields, fieldIndex++)) { if (mActions != null && !mActions.isEmpty()) { final int actionCount = mActions.size(); @@ -4333,6 +4389,7 @@ public class AccessibilityNodeInfo implements Parcelable { mUniqueId = other.mUniqueId; mBoundsInParent.set(other.mBoundsInParent); mBoundsInScreen.set(other.mBoundsInScreen); + mBoundsInWindow.set(other.mBoundsInWindow); mPackageName = other.mPackageName; mClassName = other.mClassName; mText = other.mText; @@ -4464,6 +4521,13 @@ public class AccessibilityNodeInfo implements Parcelable { mBoundsInScreen.right = parcel.readInt(); } + if (isBitSet(nonDefaultFields, fieldIndex++)) { + mBoundsInWindow.top = parcel.readInt(); + mBoundsInWindow.bottom = parcel.readInt(); + mBoundsInWindow.left = parcel.readInt(); + mBoundsInWindow.right = parcel.readInt(); + } + if (isBitSet(nonDefaultFields, fieldIndex++)) { final long standardActions = parcel.readLong(); addStandardActions(standardActions); @@ -4815,6 +4879,7 @@ public class AccessibilityNodeInfo implements Parcelable { builder.append("; boundsInParent: ").append(mBoundsInParent); builder.append("; boundsInScreen: ").append(mBoundsInScreen); + builder.append("; boundsInWindow: ").append(mBoundsInScreen); builder.append("; packageName: ").append(mPackageName); builder.append("; className: ").append(mClassName); diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java index 248420f16b80d..0d7c8b84dac03 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java @@ -46,7 +46,7 @@ public class AccessibilityNodeInfoTest { // The number of fields tested in the corresponding CTS AccessibilityNodeInfoTest: // See fullyPopulateAccessibilityNodeInfo, assertEqualsAccessibilityNodeInfo, // and assertAccessibilityNodeInfoCleared in that class. - private static final int NUM_MARSHALLED_PROPERTIES = 42; + private static final int NUM_MARSHALLED_PROPERTIES = 43; /** * The number of properties that are purposely not marshalled