diff options
10 files changed, 63 insertions, 173 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.java index 11a42413c4ff..27bffd0818e7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.java @@ -18,10 +18,8 @@ package com.android.systemui.ambient.touch; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.view.GestureDetector; import android.view.MotionEvent; @@ -30,6 +28,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.shade.ShadeViewController; import com.android.systemui.shared.system.InputChannelCompat; import com.android.systemui.statusbar.phone.CentralSurfaces; @@ -37,7 +36,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.Captor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -51,89 +49,66 @@ public class ShadeTouchHandlerTest extends SysuiTestCase { CentralSurfaces mCentralSurfaces; @Mock + ShadeViewController mShadeViewController; + + @Mock TouchHandler.TouchSession mTouchSession; ShadeTouchHandler mTouchHandler; - @Captor - ArgumentCaptor<GestureDetector.OnGestureListener> mGestureListenerCaptor; - @Captor - ArgumentCaptor<InputChannelCompat.InputEventListener> mInputListenerCaptor; - private static final int TOUCH_HEIGHT = 20; @Before public void setup() { MockitoAnnotations.initMocks(this); - - mTouchHandler = new ShadeTouchHandler(Optional.of(mCentralSurfaces), TOUCH_HEIGHT); - } - - // Verifies that a swipe down in the gesture region is captured by the shade touch handler. - @Test - public void testSwipeDown_captured() { - final boolean captured = swipe(Direction.DOWN); - - assertThat(captured).isTrue(); + mTouchHandler = new ShadeTouchHandler(Optional.of(mCentralSurfaces), mShadeViewController, + TOUCH_HEIGHT); } - // Verifies that a swipe in the upward direction is not catpured. + /** + * Verify that touches aren't handled when the bouncer is showing. + */ @Test - public void testSwipeUp_notCaptured() { - final boolean captured = swipe(Direction.UP); - - // Motion events not captured as the swipe is going in the wrong direction. - assertThat(captured).isFalse(); + public void testInactiveOnBouncer() { + when(mCentralSurfaces.isBouncerShowing()).thenReturn(true); + mTouchHandler.onSessionStart(mTouchSession); + verify(mTouchSession).pop(); } - // Verifies that a swipe down forwards captured touches to the shade window for handling. + /** + * Make sure {@link ShadeTouchHandler} + */ @Test - public void testSwipeDown_sentToShadeWindow() { - swipe(Direction.DOWN); + public void testTouchPilferingOnScroll() { + final MotionEvent motionEvent1 = Mockito.mock(MotionEvent.class); + final MotionEvent motionEvent2 = Mockito.mock(MotionEvent.class); - // Both motion events are sent for the shade window to process. - verify(mCentralSurfaces, times(2)).handleExternalShadeWindowTouch(any()); - } + final ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerArgumentCaptor = + ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class); - // Verifies that a swipe down is not forwarded to the shade window. - @Test - public void testSwipeUp_touchesNotSent() { - swipe(Direction.UP); + mTouchHandler.onSessionStart(mTouchSession); + verify(mTouchSession).registerGestureListener(gestureListenerArgumentCaptor.capture()); - // Motion events are not sent for the shade window to process as the swipe is going in the - // wrong direction. - verify(mCentralSurfaces, never()).handleExternalShadeWindowTouch(any()); + assertThat(gestureListenerArgumentCaptor.getValue() + .onScroll(motionEvent1, motionEvent2, 1, 1)) + .isTrue(); } /** - * Simulates a swipe in the given direction and returns true if the touch was intercepted by the - * touch handler's gesture listener. - * <p> - * Swipe down starts from a Y coordinate of 0 and goes downward. Swipe up starts from the edge - * of the gesture region, {@link #TOUCH_HEIGHT}, and goes upward to 0. + * Ensure touches are propagated to the {@link ShadeViewController}. */ - private boolean swipe(Direction direction) { - Mockito.clearInvocations(mTouchSession); - mTouchHandler.onSessionStart(mTouchSession); - - verify(mTouchSession).registerGestureListener(mGestureListenerCaptor.capture()); - verify(mTouchSession).registerInputListener(mInputListenerCaptor.capture()); - - final float startY = direction == Direction.UP ? TOUCH_HEIGHT : 0; - final float endY = direction == Direction.UP ? 0 : TOUCH_HEIGHT; + @Test + public void testEventPropagation() { + final MotionEvent motionEvent = Mockito.mock(MotionEvent.class); - // Send touches to the input and gesture listener. - final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, startY, 0); - final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, endY, 0); - mInputListenerCaptor.getValue().onInputEvent(event1); - mInputListenerCaptor.getValue().onInputEvent(event2); - final boolean captured = mGestureListenerCaptor.getValue().onScroll(event1, event2, 0, - startY - endY); + final ArgumentCaptor<InputChannelCompat.InputEventListener> + inputEventListenerArgumentCaptor = + ArgumentCaptor.forClass(InputChannelCompat.InputEventListener.class); - return captured; + mTouchHandler.onSessionStart(mTouchSession); + verify(mTouchSession).registerInputListener(inputEventListenerArgumentCaptor.capture()); + inputEventListenerArgumentCaptor.getValue().onInputEvent(motionEvent); + verify(mShadeViewController).handleExternalTouch(motionEvent); } - private enum Direction { - DOWN, UP, - } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/CommunalTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/CommunalTouchHandlerTest.java index e3c6deed1527..29fbee01a18b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/CommunalTouchHandlerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/CommunalTouchHandlerTest.java @@ -108,7 +108,7 @@ public class CommunalTouchHandlerTest extends SysuiTestCase { mTouchHandler.onSessionStart(mTouchSession); verify(mTouchSession).registerInputListener(inputEventListenerArgumentCaptor.capture()); inputEventListenerArgumentCaptor.getValue().onInputEvent(motionEvent); - verify(mCentralSurfaces).handleExternalShadeWindowTouch(motionEvent); + verify(mCentralSurfaces).handleDreamTouch(motionEvent); } @Test diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/ShadeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/ShadeTouchHandler.java index 9c7fc9dd307f..9ef9938ab8ad 100644 --- a/packages/SystemUI/src/com/android/systemui/ambient/touch/ShadeTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/ShadeTouchHandler.java @@ -23,8 +23,7 @@ import android.graphics.Region; import android.view.GestureDetector; import android.view.MotionEvent; -import androidx.annotation.NonNull; - +import com.android.systemui.shade.ShadeViewController; import com.android.systemui.statusbar.phone.CentralSurfaces; import java.util.Optional; @@ -38,34 +37,29 @@ import javax.inject.Named; */ public class ShadeTouchHandler implements TouchHandler { private final Optional<CentralSurfaces> mSurfaces; + private final ShadeViewController mShadeViewController; private final int mInitiationHeight; - /** - * Tracks whether or not we are capturing a given touch. Will be null before and after a touch. - */ - private Boolean mCapture; - @Inject ShadeTouchHandler(Optional<CentralSurfaces> centralSurfaces, + ShadeViewController shadeViewController, @Named(NOTIFICATION_SHADE_GESTURE_INITIATION_HEIGHT) int initiationHeight) { mSurfaces = centralSurfaces; + mShadeViewController = shadeViewController; mInitiationHeight = initiationHeight; } @Override public void onSessionStart(TouchSession session) { - if (mSurfaces.isEmpty()) { + if (mSurfaces.map(CentralSurfaces::isBouncerShowing).orElse(false)) { session.pop(); return; } - session.registerCallback(() -> mCapture = null); - session.registerInputListener(ev -> { + mShadeViewController.handleExternalTouch((MotionEvent) ev); + if (ev instanceof MotionEvent) { - if (mCapture != null && mCapture) { - mSurfaces.get().handleExternalShadeWindowTouch((MotionEvent) ev); - } if (((MotionEvent) ev).getAction() == MotionEvent.ACTION_UP) { session.pop(); } @@ -74,25 +68,15 @@ public class ShadeTouchHandler implements TouchHandler { session.registerGestureListener(new GestureDetector.SimpleOnGestureListener() { @Override - public boolean onScroll(MotionEvent e1, @NonNull MotionEvent e2, float distanceX, + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - if (mCapture == null) { - // Only capture swipes that are going downwards. - mCapture = Math.abs(distanceY) > Math.abs(distanceX) && distanceY < 0; - if (mCapture) { - // Send the initial touches over, as the input listener has already - // processed these touches. - mSurfaces.get().handleExternalShadeWindowTouch(e1); - mSurfaces.get().handleExternalShadeWindowTouch(e2); - } - } - return mCapture; + return true; } @Override - public boolean onFling(MotionEvent e1, @NonNull MotionEvent e2, float velocityX, + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - return mCapture; + return true; } }); } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java index fff0c58eecb8..1c047ddcd3d8 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java @@ -98,7 +98,7 @@ public class CommunalTouchHandler implements TouchHandler { // Notification shade window has its own logic to be visible if the hub is open, no need to // do anything here other than send touch events over. session.registerInputListener(ev -> { - surfaces.handleExternalShadeWindowTouch((MotionEvent) ev); + surfaces.handleDreamTouch((MotionEvent) ev); if (ev != null && ((MotionEvent) ev).getAction() == MotionEvent.ACTION_UP) { var unused = session.pop(); } diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt index ee7b4beec64e..22aa492dbfe8 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt @@ -123,15 +123,9 @@ constructor( private var anyBouncerShowing = false /** - * True if the shade is fully expanded and the user is not interacting with it anymore, meaning - * the hub should not receive any touch input. + * True if the shade is fully expanded, meaning the hub should not receive any touch input. * - * We need to not pause the touch handling lifecycle as soon as the shade opens because if the - * user swipes down, then back up without lifting their finger, the lifecycle will be paused - * then resumed, and resuming force-stops all active touch sessions. This means the shade will - * not receive the end of the gesture and will be stuck open. - * - * Based on [ShadeInteractor.isAnyFullyExpanded] and [ShadeInteractor.isUserInteracting]. + * Tracks [ShadeInteractor.isAnyFullyExpanded]. */ private var shadeShowing = false diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index c01b7b6f4883..6efa6334b968 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -138,11 +138,6 @@ public class NotificationShadeWindowViewController implements Dumpable { private final PanelExpansionInteractor mPanelExpansionInteractor; private final ShadeExpansionStateManager mShadeExpansionStateManager; - /** - * If {@code true}, an external touch sent in {@link #handleExternalTouch(MotionEvent)} has been - * intercepted and all future touch events for the gesture should be processed by this view. - */ - private boolean mExternalTouchIntercepted = false; private boolean mIsTrackingBarGesture = false; private boolean mIsOcclusionTransitionRunning = false; private DisableSubpixelTextTransitionListener mDisableSubpixelTextTransitionListener; @@ -260,28 +255,11 @@ public class NotificationShadeWindowViewController implements Dumpable { } /** - * Handle a touch event while dreaming or on the hub by forwarding the event to the content - * view. - * <p> - * Since important logic for handling touches lives in the dispatch/intercept phases, we - * simulate going through all of these stages before sending onTouchEvent if intercepted. - * + * Handle a touch event while dreaming by forwarding the event to the content view. * @param event The event to forward. */ - public void handleExternalTouch(MotionEvent event) { - if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { - mExternalTouchIntercepted = false; - } - - if (!mView.dispatchTouchEvent(event)) { - return; - } - if (!mExternalTouchIntercepted) { - mExternalTouchIntercepted = mView.onInterceptTouchEvent(event); - } - if (mExternalTouchIntercepted) { - mView.onTouchEvent(event); - } + public void handleDreamTouch(MotionEvent event) { + mView.dispatchTouchEvent(event); } /** Inflates the {@link R.layout#status_bar_expanded} layout and sets it up. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index 7d9742849a15..8fb552f167bc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -283,12 +283,11 @@ public interface CentralSurfaces extends Dumpable, LifecycleOwner, CoreStartable void awakenDreams(); /** - * Handle a touch event while dreaming or on the glanceable hub when the touch was initiated - * within a prescribed swipeable area. This method is provided for cases where swiping in - * certain areas should be handled by CentralSurfaces instead (e.g. swiping hub open, opening - * the notification shade over dream or hub). + * Handle a touch event while dreaming when the touch was initiated within a prescribed + * swipeable area. This method is provided for cases where swiping in certain areas of a dream + * should be handled by CentralSurfaces instead (e.g. swiping communal hub open). */ - void handleExternalShadeWindowTouch(MotionEvent event); + void handleDreamTouch(MotionEvent event); boolean isBouncerShowing(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt index d5e66ff660c6..8af7ee8389e5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt @@ -79,7 +79,7 @@ abstract class CentralSurfacesEmptyImpl : CentralSurfaces { override fun updateScrimController() {} override fun shouldIgnoreTouch() = false override fun isDeviceInteractive() = false - override fun handleExternalShadeWindowTouch(event: MotionEvent?) {} + override fun handleDreamTouch(event: MotionEvent?) {} override fun awakenDreams() {} override fun isBouncerShowing() = false override fun isBouncerShowingScrimmed() = false diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index aa55f375b2eb..5b0b46ed18d2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -2932,8 +2932,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { }; @Override - public void handleExternalShadeWindowTouch(MotionEvent event) { - getNotificationShadeWindowViewController().handleExternalTouch(event); + public void handleDreamTouch(MotionEvent event) { + getNotificationShadeWindowViewController().handleDreamTouch(event); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt index 586adbd65ce8..4a867a8ecf22 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -519,46 +519,6 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization) : } @Test - fun handleExternalTouch_intercepted_sendsOnTouch() { - // Accept dispatch and also intercept. - whenever(view.dispatchTouchEvent(any())).thenReturn(true) - whenever(view.onInterceptTouchEvent(any())).thenReturn(true) - - underTest.handleExternalTouch(DOWN_EVENT) - underTest.handleExternalTouch(MOVE_EVENT) - - // Once intercepted, both events are sent to the view. - verify(view).onTouchEvent(DOWN_EVENT) - verify(view).onTouchEvent(MOVE_EVENT) - } - - @Test - fun handleExternalTouch_notDispatched_interceptNotCalled() { - // Don't accept dispatch - whenever(view.dispatchTouchEvent(any())).thenReturn(false) - - underTest.handleExternalTouch(DOWN_EVENT) - - // Interception is not offered. - verify(view, never()).onInterceptTouchEvent(any()) - } - - @Test - fun handleExternalTouch_notIntercepted_onTouchNotSent() { - // Accept dispatch, but don't dispatch - whenever(view.dispatchTouchEvent(any())).thenReturn(true) - whenever(view.onInterceptTouchEvent(any())).thenReturn(false) - - underTest.handleExternalTouch(DOWN_EVENT) - underTest.handleExternalTouch(MOVE_EVENT) - - // Interception offered for both events, but onTouchEvent is never called. - verify(view).onInterceptTouchEvent(DOWN_EVENT) - verify(view).onInterceptTouchEvent(MOVE_EVENT) - verify(view, never()).onTouchEvent(any()) - } - - @Test fun testGetKeyguardMessageArea() = testScope.runTest { underTest.keyguardMessageArea |