Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +2 −2 Original line number Diff line number Diff line Loading @@ -85,8 +85,8 @@ import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.LaunchAnimationParameters; import com.android.systemui.statusbar.notification.FakeShadowView; import com.android.systemui.statusbar.notification.LaunchAnimationParameters; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.ShadeViewRefactor; Loading Loading @@ -3615,7 +3615,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.INPUT) protected boolean isInsideQsHeader(MotionEvent ev) { mQsHeader.getBoundsOnScreen(mQsHeaderBound); return mQsHeaderBound.contains((int) ev.getX(), (int) ev.getY()); return mQsHeaderBound.contains((int) ev.getRawX(), (int) ev.getRawY()); } @ShadeViewRefactor(RefactorComponent.INPUT) Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +3 −3 Original line number Diff line number Diff line Loading @@ -2816,12 +2816,12 @@ public class NotificationPanelViewController extends PanelViewController { return false; } View header = mKeyguardShowing || mQs == null ? mKeyguardStatusBar : mQs.getHeader(); int frameTop = mKeyguardShowing || mQs == null ? 0 : mQsFrame.getTop(); mQsInterceptRegion.set( /* left= */ (int) mQsFrame.getX(), /* top= */ header.getTop(), /* top= */ header.getTop() + frameTop, /* right= */ (int) mQsFrame.getX() + mQsFrame.getWidth(), /* bottom= */ header.getBottom()); /* bottom= */ header.getBottom() + frameTop); // Also allow QS to intercept if the touch is near the notch. mStatusBarTouchableRegionManager.updateRegionForNotch(mQsInterceptRegion); final boolean onHeader = mQsInterceptRegion.contains((int) x, (int) y); Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +66 −0 Original line number Diff line number Diff line Loading @@ -34,15 +34,20 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.graphics.Rect; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.MathUtils; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import androidx.test.annotation.UiThreadTest; import androidx.test.filters.SmallTest; Loading Loading @@ -572,9 +577,70 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { assertEquals(0, mStackScroller.getSpeedBumpIndex()); } @Test public void testInsideQSHeader_noOffset() { ViewGroup qsHeader = mock(ViewGroup.class); Rect boundsOnScreen = new Rect(0, 0, 1000, 1000); mockBoundsOnScreen(qsHeader, boundsOnScreen); mStackScroller.setQsHeader(qsHeader); mStackScroller.setLeftTopRightBottom(0, 0, 2000, 2000); MotionEvent event1 = transformEventForView(createMotionEvent(100f, 100f), mStackScroller); assertTrue(mStackScroller.isInsideQsHeader(event1)); MotionEvent event2 = transformEventForView(createMotionEvent(1100f, 100f), mStackScroller); assertFalse(mStackScroller.isInsideQsHeader(event2)); } @Test public void testInsideQSHeader_Offset() { ViewGroup qsHeader = mock(ViewGroup.class); Rect boundsOnScreen = new Rect(100, 100, 1000, 1000); mockBoundsOnScreen(qsHeader, boundsOnScreen); mStackScroller.setQsHeader(qsHeader); mStackScroller.setLeftTopRightBottom(200, 200, 2000, 2000); MotionEvent event1 = transformEventForView(createMotionEvent(50f, 50f), mStackScroller); assertFalse(mStackScroller.isInsideQsHeader(event1)); MotionEvent event2 = transformEventForView(createMotionEvent(150f, 150f), mStackScroller); assertTrue(mStackScroller.isInsideQsHeader(event2)); MotionEvent event3 = transformEventForView(createMotionEvent(250f, 250f), mStackScroller); assertTrue(mStackScroller.isInsideQsHeader(event2)); } private void setBarStateForTest(int state) { // Can't inject this through the listener or we end up on the actual implementation // rather than the mock because the spy just coppied the anonymous inner /shruggie. mStackScroller.setStatusBarState(state); } private static void mockBoundsOnScreen(View view, Rect bounds) { doAnswer(invocation -> { Rect out = invocation.getArgument(0); out.set(bounds); return null; }).when(view).getBoundsOnScreen(any()); } private static MotionEvent transformEventForView(MotionEvent event, View view) { // From `ViewGroup#dispatchTransformedTouchEvent` MotionEvent transformed = event.copy(); transformed.offsetLocation(-view.getTop(), -view.getLeft()); return transformed; } private static MotionEvent createMotionEvent(float x, float y) { return MotionEvent.obtain( /* downTime= */0, /* eventTime= */0, MotionEvent.ACTION_DOWN, x, y, /* metaState= */0 ); } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +2 −2 Original line number Diff line number Diff line Loading @@ -85,8 +85,8 @@ import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.LaunchAnimationParameters; import com.android.systemui.statusbar.notification.FakeShadowView; import com.android.systemui.statusbar.notification.LaunchAnimationParameters; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.ShadeViewRefactor; Loading Loading @@ -3615,7 +3615,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.INPUT) protected boolean isInsideQsHeader(MotionEvent ev) { mQsHeader.getBoundsOnScreen(mQsHeaderBound); return mQsHeaderBound.contains((int) ev.getX(), (int) ev.getY()); return mQsHeaderBound.contains((int) ev.getRawX(), (int) ev.getRawY()); } @ShadeViewRefactor(RefactorComponent.INPUT) Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +3 −3 Original line number Diff line number Diff line Loading @@ -2816,12 +2816,12 @@ public class NotificationPanelViewController extends PanelViewController { return false; } View header = mKeyguardShowing || mQs == null ? mKeyguardStatusBar : mQs.getHeader(); int frameTop = mKeyguardShowing || mQs == null ? 0 : mQsFrame.getTop(); mQsInterceptRegion.set( /* left= */ (int) mQsFrame.getX(), /* top= */ header.getTop(), /* top= */ header.getTop() + frameTop, /* right= */ (int) mQsFrame.getX() + mQsFrame.getWidth(), /* bottom= */ header.getBottom()); /* bottom= */ header.getBottom() + frameTop); // Also allow QS to intercept if the touch is near the notch. mStatusBarTouchableRegionManager.updateRegionForNotch(mQsInterceptRegion); final boolean onHeader = mQsInterceptRegion.contains((int) x, (int) y); Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +66 −0 Original line number Diff line number Diff line Loading @@ -34,15 +34,20 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.graphics.Rect; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.MathUtils; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import androidx.test.annotation.UiThreadTest; import androidx.test.filters.SmallTest; Loading Loading @@ -572,9 +577,70 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { assertEquals(0, mStackScroller.getSpeedBumpIndex()); } @Test public void testInsideQSHeader_noOffset() { ViewGroup qsHeader = mock(ViewGroup.class); Rect boundsOnScreen = new Rect(0, 0, 1000, 1000); mockBoundsOnScreen(qsHeader, boundsOnScreen); mStackScroller.setQsHeader(qsHeader); mStackScroller.setLeftTopRightBottom(0, 0, 2000, 2000); MotionEvent event1 = transformEventForView(createMotionEvent(100f, 100f), mStackScroller); assertTrue(mStackScroller.isInsideQsHeader(event1)); MotionEvent event2 = transformEventForView(createMotionEvent(1100f, 100f), mStackScroller); assertFalse(mStackScroller.isInsideQsHeader(event2)); } @Test public void testInsideQSHeader_Offset() { ViewGroup qsHeader = mock(ViewGroup.class); Rect boundsOnScreen = new Rect(100, 100, 1000, 1000); mockBoundsOnScreen(qsHeader, boundsOnScreen); mStackScroller.setQsHeader(qsHeader); mStackScroller.setLeftTopRightBottom(200, 200, 2000, 2000); MotionEvent event1 = transformEventForView(createMotionEvent(50f, 50f), mStackScroller); assertFalse(mStackScroller.isInsideQsHeader(event1)); MotionEvent event2 = transformEventForView(createMotionEvent(150f, 150f), mStackScroller); assertTrue(mStackScroller.isInsideQsHeader(event2)); MotionEvent event3 = transformEventForView(createMotionEvent(250f, 250f), mStackScroller); assertTrue(mStackScroller.isInsideQsHeader(event2)); } private void setBarStateForTest(int state) { // Can't inject this through the listener or we end up on the actual implementation // rather than the mock because the spy just coppied the anonymous inner /shruggie. mStackScroller.setStatusBarState(state); } private static void mockBoundsOnScreen(View view, Rect bounds) { doAnswer(invocation -> { Rect out = invocation.getArgument(0); out.set(bounds); return null; }).when(view).getBoundsOnScreen(any()); } private static MotionEvent transformEventForView(MotionEvent event, View view) { // From `ViewGroup#dispatchTransformedTouchEvent` MotionEvent transformed = event.copy(); transformed.offsetLocation(-view.getTop(), -view.getLeft()); return transformed; } private static MotionEvent createMotionEvent(float x, float y) { return MotionEvent.obtain( /* downTime= */0, /* eventTime= */0, MotionEvent.ACTION_DOWN, x, y, /* metaState= */0 ); } }