diff options
| -rw-r--r-- | core/java/android/view/View.java | 2 | ||||
| -rw-r--r-- | core/java/android/view/ViewGroup.java | 21 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java | 83 |
3 files changed, 91 insertions, 15 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 03c40cb03d6f..bed5eea2d199 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1494,7 +1494,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public static final int SCROLL_CAPTURE_HINT_AUTO = 0; /** - * Explicitly exclcude this view as a potential scroll capture target. The system will not + * Explicitly exclude this view as a potential scroll capture target. The system will not * consider it. Mutually exclusive with {@link #SCROLL_CAPTURE_HINT_INCLUDE}, which this flag * takes precedence over. * diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 04e2cdee56a0..a02281be1228 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -7490,12 +7490,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @NonNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets) { - // copy local visible rect for modification and dispatch - final Rect rect = getTempRect(); - rect.set(localVisibleRect); - - if (getClipToPadding()) { - rect.inset(mPaddingLeft, mPaddingTop, mPaddingRight, mPaddingBottom); + if (getClipToPadding() && !localVisibleRect.intersect(mPaddingLeft, mPaddingTop, + (mRight - mLeft) - mPaddingRight, (mBottom - mTop) - mPaddingBottom)) { + return; } // Dispatch to self first. @@ -7506,6 +7503,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return; } + final Rect tmpRect = getTempRect(); final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); @@ -7518,8 +7516,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // If the resulting rectangle is not empty, the request is forwarded to the child. // copy local visible rect for modification and dispatch - final Rect childVisibleRect = getTempRect(); - childVisibleRect.set(localVisibleRect); + tmpRect.set(localVisibleRect); // transform to child coords final Point childWindowOffset = getTempPoint(); @@ -7528,20 +7525,18 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final int dx = child.mLeft - mScrollX; final int dy = child.mTop - mScrollY; - childVisibleRect.offset(-dx, -dy); + tmpRect.offset(-dx, -dy); childWindowOffset.offset(dx, dy); boolean rectIsVisible = true; // Clip to child bounds if (getClipChildren()) { - rectIsVisible = childVisibleRect.intersect(0, 0, child.getWidth(), - child.getHeight()); + rectIsVisible = tmpRect.intersect(0, 0, child.getWidth(), child.getHeight()); } - // Clip to child padding. if (rectIsVisible) { - child.dispatchScrollCaptureSearch(childVisibleRect, childWindowOffset, targets); + child.dispatchScrollCaptureSearch(tmpRect, childWindowOffset, targets); } } } diff --git a/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java b/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java index 695eb0ced756..25608c328f95 100644 --- a/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java +++ b/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java @@ -33,7 +33,6 @@ import android.os.CancellationSignal; import android.platform.test.annotations.Presubmit; import androidx.annotation.NonNull; -import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import androidx.test.filters.SmallTest; @@ -355,6 +354,54 @@ public class ViewGroupScrollCaptureTest { target.getContainingView().getScrollCaptureHint()); } + /** + * Tests the effect of padding on scroll capture search dispatch. + * <p> + * Verifies computation of child visible bounds with padding. + */ + @MediumTest + @Test + public void testOnScrollCaptureSearch_withPadding() { + final Context context = getInstrumentation().getContext(); + + Rect windowBounds = new Rect(0, 0, 200, 200); + Point windowOffset = new Point(0, 0); + + final MockViewGroup parent = new MockViewGroup(context, 0, 0, 200, 200); + parent.setPadding(25, 50, 25, 50); + parent.setClipToPadding(true); // (default) + + final MockView view1 = new MockView(context, 0, -100, 200, 100); + parent.addView(view1); + + final MockView view2 = new MockView(context, 0, 0, 200, 200); + parent.addView(view2); + + final MockViewGroup view3 = new MockViewGroup(context, 0, 100, 200, 300); + parent.addView(view3); + view3.setPadding(25, 25, 25, 25); + view3.setClipToPadding(true); + + // Where targets are added + final ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(DIRECT_EXECUTOR); + + // Dispatch to the ViewGroup + parent.dispatchScrollCaptureSearch(windowBounds, windowOffset, results::addTarget); + + // Verify padding (with clipToPadding) is subtracted from visibleBounds + parent.assertOnScrollCaptureSearchLastArgs(new Rect(25, 50, 175, 150), new Point(0, 0)); + + view1.assertOnScrollCaptureSearchLastArgs( + new Rect(25, 150, 175, 200), new Point(0, -100)); + + view2.assertOnScrollCaptureSearchLastArgs( + new Rect(25, 50, 175, 150), new Point(0, 0)); + + // Account for padding on view3 as well (top == 25px) + view3.assertOnScrollCaptureSearchLastArgs( + new Rect(25, 25, 175, 50), new Point(0, 100)); + } + public static final class MockView extends View { private ScrollCaptureCallback mInternalCallback; @@ -362,6 +409,8 @@ public class ViewGroupScrollCaptureTest { private Rect mDispatchScrollCaptureSearchLastLocalVisibleRect; private Point mDispatchScrollCaptureSearchLastWindowOffset; private int mCreateScrollCaptureCallbackInternalCount; + private Rect mOnScrollCaptureSearchLastLocalVisibleRect; + private Point mOnScrollCaptureSearchLastWindowOffset; MockView(Context context) { this(context, /* left */ 0, /* top */0, /* right */ 0, /* bottom */0); @@ -407,6 +456,21 @@ public class ViewGroupScrollCaptureTest { } @Override + public void onScrollCaptureSearch(Rect localVisibleRect, Point windowOffset, + Consumer<ScrollCaptureTarget> targets) { + super.onScrollCaptureSearch(localVisibleRect, windowOffset, targets); + mOnScrollCaptureSearchLastLocalVisibleRect = new Rect(localVisibleRect); + mOnScrollCaptureSearchLastWindowOffset = new Point(windowOffset); + } + + void assertOnScrollCaptureSearchLastArgs(Rect localVisibleRect, Point windowOffset) { + assertEquals("arg localVisibleRect was incorrect.", + localVisibleRect, mOnScrollCaptureSearchLastLocalVisibleRect); + assertEquals("arg windowOffset was incorrect.", + windowOffset, mOnScrollCaptureSearchLastWindowOffset); + } + + @Override public void dispatchScrollCaptureSearch(Rect localVisibleRect, Point windowOffset, Consumer<ScrollCaptureTarget> results) { mDispatchScrollCaptureSearchNumCalls++; @@ -449,6 +513,8 @@ public class ViewGroupScrollCaptureTest { public static final class MockViewGroup extends ViewGroup { private ScrollCaptureCallback mInternalCallback; + private Rect mOnScrollCaptureSearchLastLocalVisibleRect; + private Point mOnScrollCaptureSearchLastWindowOffset; MockViewGroup(Context context) { this(context, /* left */ 0, /* top */0, /* right */ 0, /* bottom */0); @@ -477,6 +543,21 @@ public class ViewGroupScrollCaptureTest { } @Override + public void onScrollCaptureSearch(Rect localVisibleRect, Point windowOffset, + Consumer<ScrollCaptureTarget> targets) { + super.onScrollCaptureSearch(localVisibleRect, windowOffset, targets); + mOnScrollCaptureSearchLastLocalVisibleRect = new Rect(localVisibleRect); + mOnScrollCaptureSearchLastWindowOffset = new Point(windowOffset); + } + + void assertOnScrollCaptureSearchLastArgs(Rect localVisibleRect, Point windowOffset) { + assertEquals("arg localVisibleRect was incorrect.", + localVisibleRect, mOnScrollCaptureSearchLastLocalVisibleRect); + assertEquals("arg windowOffset was incorrect.", + windowOffset, mOnScrollCaptureSearchLastWindowOffset); + } + + @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // We don't layout this view. } |