Account for padding in dispatchScrollCaptureSearch
When dispatching to self, ViewGroup is not applying padding to localVisibleRect, only when dispatching to child views. Also when deducting padding from the visible bounds, it must be intersected with bounds, not subtracted. Test: atest ViewGroupScrollCaptureTest Bug: 185153400 Change-Id: Ib92e4c552fbe02fd863123f166878e19b8b1c952
This commit is contained in:
@@ -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.
|
||||
*
|
||||
|
||||
@@ -7479,12 +7479,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.
|
||||
@@ -7495,6 +7492,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);
|
||||
@@ -7507,8 +7505,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();
|
||||
@@ -7517,20 +7514,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -343,6 +342,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;
|
||||
|
||||
@@ -350,6 +397,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);
|
||||
@@ -394,6 +443,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) {
|
||||
@@ -437,6 +501,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);
|
||||
@@ -464,6 +530,21 @@ public class ViewGroupScrollCaptureTest {
|
||||
return mInternalCallback;
|
||||
}
|
||||
|
||||
@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.
|
||||
|
||||
Reference in New Issue
Block a user