diff options
2 files changed, 78 insertions, 9 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index b9628e95c436..48e69893cd7b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -3710,7 +3710,7 @@ public class NotificationStackScrollLayout if (!isScrollingEnabled()) { return false; } - if (isInsideQsHeader(ev) && !mIsBeingDragged) { + if (!isInScrollableRegion(ev) && !mIsBeingDragged) { return false; } mForcedScroll = null; @@ -3878,11 +3878,26 @@ public class NotificationStackScrollLayout return mFlingAfterUpEvent; } - protected boolean isInsideQsHeader(MotionEvent ev) { - if (SceneContainerFlag.isEnabled()) { - return ev.getY() < mAmbientState.getStackTop(); + /** Is this touch event inside the scrollable region? */ + @VisibleForTesting + boolean isInScrollableRegion(MotionEvent ev) { + if (!SceneContainerFlag.isEnabled()) { + return !isInsideQsHeader(ev); + } + ShadeScrimShape shape = mScrollViewFields.getScrimClippingShape(); + if (shape == null) { + return true; // When there is no scrim, consider this event scrollable. } + ShadeScrimBounds bounds = shape.getBounds(); + return ev.getX() >= bounds.getLeft() + && ev.getX() <= bounds.getRight() + && ev.getY() >= bounds.getTop() + && ev.getY() <= bounds.getBottom(); + } + + protected boolean isInsideQsHeader(MotionEvent ev) { + SceneContainerFlag.assertInLegacyMode(); if (QSComposeFragment.isEnabled()) { if (mQSHeaderBoundsProvider == null) { return false; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index a18de68dfcfc..a06f4d2d2d80 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -95,6 +95,8 @@ import com.android.systemui.statusbar.notification.footer.ui.view.FooterView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun; +import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds; +import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; @@ -893,7 +895,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test @DisableFlags({QSComposeFragment.FLAG_NAME, NewQsUI.FLAG_NAME}) - @DisableSceneContainer // TODO(b/312473478): address lack of QS Header + @DisableSceneContainer public void testInsideQSHeader_noOffset() { ViewGroup qsHeader = mock(ViewGroup.class); Rect boundsOnScreen = new Rect(0, 0, 1000, 1000); @@ -911,7 +913,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test @DisableFlags({QSComposeFragment.FLAG_NAME, NewQsUI.FLAG_NAME}) - @DisableSceneContainer // TODO(b/312473478): address lack of QS Header + @DisableSceneContainer public void testInsideQSHeader_Offset() { ViewGroup qsHeader = mock(ViewGroup.class); Rect boundsOnScreen = new Rect(100, 100, 1000, 1000); @@ -932,7 +934,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test @EnableFlags({QSComposeFragment.FLAG_NAME, NewQsUI.FLAG_NAME}) - @DisableSceneContainer // TODO(b/312473478): address lack of QS Header + @DisableSceneContainer public void testInsideQSHeader_noOffset_qsCompose() { ViewGroup qsHeader = mock(ViewGroup.class); Rect boundsOnScreen = new Rect(0, 0, 1000, 1000); @@ -959,7 +961,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test @EnableFlags({QSComposeFragment.FLAG_NAME, NewQsUI.FLAG_NAME}) - @DisableSceneContainer // TODO(b/312473478): address lack of QS Header + @DisableSceneContainer public void testInsideQSHeader_Offset_qsCompose() { ViewGroup qsHeader = mock(ViewGroup.class); Rect boundsOnScreen = new Rect(100, 100, 1000, 1000); @@ -988,6 +990,53 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { } @Test + @EnableSceneContainer + public void testIsInsideScrollableRegion_noScrim() { + mStackScroller.setLeftTopRightBottom(0, 0, 2000, 2000); + + MotionEvent event = transformEventForView(createMotionEvent(250f, 250f), mStackScroller); + assertThat(mStackScroller.isInScrollableRegion(event)).isTrue(); + } + + @Test + @EnableSceneContainer + public void testIsInsideScrollableRegion_noOffset() { + mStackScroller.setLeftTopRightBottom(0, 0, 1000, 2000); + mStackScroller.setScrimClippingShape(createScrimShape(100, 500, 900, 2000)); + + MotionEvent event1 = transformEventForView(createMotionEvent(500f, 400f), mStackScroller); + assertThat(mStackScroller.isInScrollableRegion(event1)).isFalse(); + + MotionEvent event2 = transformEventForView(createMotionEvent(50, 1000f), mStackScroller); + assertThat(mStackScroller.isInScrollableRegion(event2)).isFalse(); + + MotionEvent event3 = transformEventForView(createMotionEvent(950f, 1000f), mStackScroller); + assertThat(mStackScroller.isInScrollableRegion(event3)).isFalse(); + + MotionEvent event4 = transformEventForView(createMotionEvent(500f, 1000f), mStackScroller); + assertThat(mStackScroller.isInScrollableRegion(event4)).isTrue(); + } + + @Test + @EnableSceneContainer + public void testIsInsideScrollableRegion_offset() { + mStackScroller.setLeftTopRightBottom(1000, 0, 2000, 2000); + mStackScroller.setScrimClippingShape(createScrimShape(100, 500, 900, 2000)); + + MotionEvent event1 = transformEventForView(createMotionEvent(1500f, 400f), mStackScroller); + assertThat(mStackScroller.isInScrollableRegion(event1)).isFalse(); + + MotionEvent event2 = transformEventForView(createMotionEvent(1050, 1000f), mStackScroller); + assertThat(mStackScroller.isInScrollableRegion(event2)).isFalse(); + + MotionEvent event3 = transformEventForView(createMotionEvent(1950f, 1000f), mStackScroller); + assertThat(mStackScroller.isInScrollableRegion(event3)).isFalse(); + + MotionEvent event4 = transformEventForView(createMotionEvent(1500f, 1000f), mStackScroller); + assertThat(mStackScroller.isInScrollableRegion(event4)).isTrue(); + } + + @Test @DisableSceneContainer // TODO(b/312473478): address disabled test public void setFractionToShade_recomputesStackHeight() { mStackScroller.setFractionToShade(1f); @@ -1438,7 +1487,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { private static MotionEvent transformEventForView(MotionEvent event, View view) { // From `ViewGroup#dispatchTransformedTouchEvent` MotionEvent transformed = event.copy(); - transformed.offsetLocation(-view.getTop(), -view.getLeft()); + transformed.offsetLocation(/* deltaX = */-view.getLeft(), /* deltaY = */ -view.getTop()); return transformed; } @@ -1474,4 +1523,9 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { } private abstract static class BooleanConsumer implements Consumer<Boolean> { } + + private ShadeScrimShape createScrimShape(int left, int top, int right, int bottom) { + ShadeScrimBounds bounds = new ShadeScrimBounds(left, top, right, bottom); + return new ShadeScrimShape(bounds, 0, 0); + } } |