Merge "Intercept swipe up touches" into main
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index adff590..7f0b899 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -586,6 +586,8 @@
private boolean mGestureWaitForTouchSlop;
private boolean mIgnoreXTouchSlop;
private boolean mExpandLatencyTracking;
+ private boolean mUseExternalTouch = false;
+
/**
* Whether we're waking up and will play the delayed doze animation in
* {@link NotificationWakeUpCoordinator}. If so, we'll want to keep the clock centered until the
@@ -4114,12 +4116,22 @@
/** Sends an external (e.g. Status Bar) intercept touch event to the Shade touch handler. */
boolean handleExternalInterceptTouch(MotionEvent event) {
- return mTouchHandler.onInterceptTouchEvent(event);
+ try {
+ mUseExternalTouch = true;
+ return mTouchHandler.onInterceptTouchEvent(event);
+ } finally {
+ mUseExternalTouch = false;
+ }
}
@Override
public boolean handleExternalTouch(MotionEvent event) {
- return mTouchHandler.onTouchEvent(event);
+ try {
+ mUseExternalTouch = true;
+ return mTouchHandler.onTouchEvent(event);
+ } finally {
+ mUseExternalTouch = false;
+ }
}
@Override
@@ -4706,9 +4718,20 @@
public final class TouchHandler implements View.OnTouchListener, Gefingerpoken {
private long mLastTouchDownTime = -1L;
- /** @see ViewGroup#onInterceptTouchEvent(MotionEvent) */
+ /**
+ * With the shade and lockscreen being separated in the view hierarchy, touch handling now
+ * originates with the parent window through {@link #handleExternalTouch}. This allows for
+ * parity with the legacy hierarchy while not undertaking a massive refactoring of touch
+ * handling.
+ *
+ * @see NotificationShadeWindowViewController#didNotificationPanelInterceptEvent
+ */
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL) && !mUseExternalTouch) {
+ return false;
+ }
+
mShadeLog.logMotionEvent(event, "NPVC onInterceptTouchEvent");
if (mQsController.disallowTouches()) {
mShadeLog.logMotionEvent(event,
@@ -4861,8 +4884,20 @@
return onTouchEvent(event);
}
+ /**
+ * With the shade and lockscreen being separated in the view hierarchy, touch handling now
+ * originates with the parent window through {@link #handleExternalTouch}. This allows for
+ * parity with the legacy hierarchy while not undertaking a massive refactoring of touch
+ * handling.
+ *
+ * @see NotificationShadeWindowViewController#didNotificationPanelInterceptEvent
+ */
@Override
public boolean onTouchEvent(MotionEvent event) {
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL) && !mUseExternalTouch) {
+ return false;
+ }
+
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (event.getDownTime() == mLastTouchDownTime) {
// An issue can occur when swiping down after unlock, where multiple down
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 880ba92..96fae14 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -267,6 +267,9 @@
}
mView.setLayoutInsetsController(mNotificationInsetsController);
mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() {
+ boolean mUseDragDownHelperForTouch = false;
+ boolean mLastInterceptWasDragDownHelper = false;
+
@Override
public Boolean handleDispatchTouchEvent(MotionEvent ev) {
if (mStatusBarViewController == null) { // Fix for b/192490822
@@ -360,10 +363,8 @@
);
// In case we start outside of the view bounds (below the status bar), we need to
- // dispatch
- // the touch manually as the view system can't accommodate for touches outside of
- // the
- // regular view bounds.
+ // dispatch the touch manually as the view system can't accommodate for touches
+ // outside of the regular view bounds.
if (isDown && ev.getY() >= mView.getBottom()) {
mExpandingBelowNotch = true;
expandingBelowNotch = true;
@@ -405,6 +406,15 @@
@Override
public boolean shouldInterceptTouchEvent(MotionEvent ev) {
+ boolean intercepted = shouldInterceptTouchEventInternal(ev);
+ if (intercepted) {
+ mUseDragDownHelperForTouch = mLastInterceptWasDragDownHelper;
+ }
+ return intercepted;
+ }
+
+ private boolean shouldInterceptTouchEventInternal(MotionEvent ev) {
+ mLastInterceptWasDragDownHelper = false;
if (mStatusBarStateController.isDozing() && !mDozeServiceHost.isPulsing()
&& !mDockManager.isDocked()) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
@@ -431,19 +441,36 @@
}
if (mNotificationPanelViewController.isFullyExpanded()
- && mDragDownHelper.isDragDownEnabled()
&& !mService.isBouncerShowing()
&& !mStatusBarStateController.isDozing()) {
- boolean result = mDragDownHelper.onInterceptTouchEvent(ev);
- if (result) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- mShadeLogger.d("NSWVC: drag down helper intercepted");
+ if (mDragDownHelper.isDragDownEnabled()) {
+ // This handles drag down over lockscreen
+ boolean result = mDragDownHelper.onInterceptTouchEvent(ev);
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ if (result) {
+ mLastInterceptWasDragDownHelper = true;
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ mShadeLogger.d("NSWVC: drag down helper intercepted");
+ }
+ } else if (didNotificationPanelInterceptEvent(ev)) {
+ return true;
+ }
+ } else {
+ if (result) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ mShadeLogger.d("NSWVC: drag down helper intercepted");
+ }
+ }
+ }
+ return result;
+ } else {
+ // This else handles interactions on the full shade while unlocked
+ if (didNotificationPanelInterceptEvent(ev)) {
+ return true;
}
}
- return result;
- } else {
- return false;
}
+ return false;
}
@Override
@@ -451,7 +478,9 @@
MotionEvent cancellation = MotionEvent.obtain(ev);
cancellation.setAction(MotionEvent.ACTION_CANCEL);
mStackScrollLayout.onInterceptTouchEvent(cancellation);
- mNotificationPanelViewController.handleExternalInterceptTouch(cancellation);
+ if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ mNotificationPanelViewController.handleExternalInterceptTouch(cancellation);
+ }
cancellation.recycle();
}
@@ -461,18 +490,27 @@
if (mStatusBarStateController.isDozing()) {
handled = !mDozeServiceHost.isPulsing();
}
-
if (mStatusBarKeyguardViewManager.onTouch(ev)) {
return true;
}
-
- if (mDragDownHelper.isDragDownEnabled()
- || mDragDownHelper.isDraggingDown()) {
- // we still want to finish our drag down gesture when locking the screen
- return mDragDownHelper.onTouchEvent(ev) || handled;
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ if (mLastInterceptWasDragDownHelper && (mDragDownHelper.isDraggingDown())) {
+ // we still want to finish our drag down gesture when locking the screen
+ handled |= mDragDownHelper.onTouchEvent(ev) || handled;
+ }
+ if (!handled && mNotificationPanelViewController.handleExternalTouch(ev)) {
+ return true;
+ }
} else {
- return handled;
+ if (mDragDownHelper.isDragDownEnabled()
+ || mDragDownHelper.isDraggingDown()) {
+ // we still want to finish our drag down gesture when locking the screen
+ return mDragDownHelper.onTouchEvent(ev) || handled;
+ } else {
+ return handled;
+ }
}
+ return handled;
}
@Override
@@ -520,6 +558,20 @@
mDepthController.onPanelExpansionChanged(currentState);
}
+ private boolean didNotificationPanelInterceptEvent(MotionEvent ev) {
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ // Since NotificationStackScrollLayout is now a sibling of notification_panel, we need
+ // to also ask NotificationPanelViewController directly, in order to process swipe up
+ // events originating from notifications
+ if (mNotificationPanelViewController.handleExternalInterceptTouch(ev)) {
+ mShadeLogger.d("NSWVC: NPVC intercepted");
+ return true;
+ }
+ }
+
+ return false;
+ }
+
public NotificationShadeWindowView getView() {
return mView;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index ff0d78f8..d653cb4 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -70,6 +70,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
@@ -1776,7 +1777,9 @@
// Dragging down on the lockscreen statusbar should prohibit other interactions
// immediately, otherwise we'll wait on the touchslop. This is to allow
// dragging down to expanded quick settings directly on the lockscreen.
- mPanelView.getParent().requestDisallowInterceptTouchEvent(true);
+ if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ mPanelView.getParent().requestDisallowInterceptTouchEvent(true);
+ }
}
if (mExpansionAnimator != null) {
mInitialHeightOnTouch = mExpansionHeight;
@@ -1819,7 +1822,9 @@
&& Math.abs(h) > Math.abs(x - mInitialTouchX)
&& shouldQuickSettingsIntercept(
mInitialTouchX, mInitialTouchY, h)) {
- mPanelView.getParent().requestDisallowInterceptTouchEvent(true);
+ if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ mPanelView.getParent().requestDisallowInterceptTouchEvent(true);
+ }
mShadeLog.onQsInterceptMoveQsTrackingEnabled(h);
setTracking(true);
traceQsJank(true, 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 bbca234..d968e71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -1545,7 +1545,9 @@
return (v, event) -> {
mAutoHideController.checkUserAutoHide(event);
mRemoteInputManager.checkRemoteInputOutside(event);
- mShadeController.onStatusBarTouch(event);
+ if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+ mShadeController.onStatusBarTouch(event);
+ }
return getNotificationShadeWindowView().onTouchEvent(event);
};
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 6dadd4c3..227f653 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -59,6 +59,7 @@
import com.android.keyguard.FaceAuthApiRequestReason;
import com.android.systemui.DejankUtils;
import com.android.systemui.R;
+import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.shared.model.WakeSleepReason;
import com.android.systemui.keyguard.shared.model.WakefulnessModel;
import com.android.systemui.keyguard.shared.model.WakefulnessState;
@@ -1064,7 +1065,18 @@
mEmptySpaceClickListenerCaptor.getValue().onEmptySpaceClicked(0, 0);
verify(mUpdateMonitor, never()).requestFaceAuth(anyString());
+ }
+ @Test
+ public void nsslFlagEnabled_allowOnlyExternalTouches() {
+ when(mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)).thenReturn(true);
+
+ // This sets the dozing state that is read when onMiddleClicked is eventually invoked.
+ mTouchHandler.onTouch(mock(View.class), mDownMotionEvent);
+ verify(mQsController, never()).disallowTouches();
+
+ mNotificationPanelViewController.handleExternalInterceptTouch(mDownMotionEvent);
+ verify(mQsController).disallowTouches();
}
@Test
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 39fe498..3da5f6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -48,6 +48,7 @@
import com.android.systemui.log.BouncerLogger
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
+import com.android.systemui.statusbar.DragDownHelper
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationInsetsController
import com.android.systemui.statusbar.NotificationShadeDepthController
@@ -124,6 +125,7 @@
private lateinit var unfoldTransitionProgressProvider:
Optional<UnfoldTransitionProgressProvider>
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
+ @Mock lateinit var dragDownHelper: DragDownHelper
@Mock
lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
@Mock lateinit var keyEventInteractor: KeyEventInteractor
@@ -137,6 +139,8 @@
private lateinit var testScope: TestScope
+ private lateinit var featureFlags: FakeFeatureFlags
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -150,12 +154,13 @@
whenever(keyguardTransitionInteractor.lockscreenToDreamingTransition)
.thenReturn(emptyFlow<TransitionStep>())
- val featureFlags = FakeFeatureFlags()
+ featureFlags = FakeFeatureFlags()
featureFlags.set(Flags.TRACKPAD_GESTURE_COMMON, true)
featureFlags.set(Flags.TRACKPAD_GESTURE_FEATURES, false)
featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true)
featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false)
+ featureFlags.set(Flags.MIGRATE_NSSL, false)
testScope = TestScope()
fakeClock = FakeSystemClock()
@@ -206,6 +211,7 @@
keyEventInteractor,
)
underTest.setupExpandedStatusBar()
+ underTest.setDragDownHelper(dragDownHelper)
interactionEventHandlerCaptor = ArgumentCaptor.forClass(InteractionEventHandler::class.java)
verify(view).setInteractionEventHandler(interactionEventHandlerCaptor.capture())
@@ -347,9 +353,8 @@
testScope.runTest {
// GIVEN touch dispatcher in a state that returns true
underTest.setStatusBarViewController(phoneStatusBarViewController)
- whenever(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()).thenReturn(
- true
- )
+ whenever(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
+ .thenReturn(true)
assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isTrue()
// WHEN launch animation is running for 2 seconds
@@ -381,6 +386,32 @@
}
@Test
+ fun shouldInterceptTouchEvent_notificationPanelViewControllerShouldIntercept() {
+ // GIVEN not dozing
+ whenever(sysuiStatusBarStateController.isDozing()).thenReturn(false)
+ // AND alternate bouncer doesn't want the touch
+ whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT))
+ .thenReturn(false)
+ // AND the lock icon doesn't want the touch
+ whenever(lockIconViewController.onInterceptTouchEvent(DOWN_EVENT)).thenReturn(false)
+ // AND the notification panel can accept touches
+ whenever(notificationPanelViewController.isFullyExpanded()).thenReturn(true)
+ whenever(dragDownHelper.isDragDownEnabled).thenReturn(true)
+ whenever(centralSurfaces.isBouncerShowing()).thenReturn(false)
+
+ // AND the drag down helper doesn't want the touch (to pull the shade down)
+ whenever(dragDownHelper.onInterceptTouchEvent(DOWN_EVENT)).thenReturn(false)
+
+ featureFlags.set(Flags.MIGRATE_NSSL, true)
+
+ // WHEN asked if should intercept touch
+ interactionEventHandler.shouldInterceptTouchEvent(DOWN_EVENT)
+
+ // Verify that NPVC gets a chance to use the touch
+ verify(notificationPanelViewController).handleExternalInterceptTouch(DOWN_EVENT)
+ }
+
+ @Test
fun testGetKeyguardMessageArea() =
testScope.runTest {
underTest.keyguardMessageArea
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 3031658..04c4b45 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -164,6 +164,7 @@
featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true)
featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false)
+ featureFlags.set(Flags.MIGRATE_NSSL, false)
testScope = TestScope()
controller =
NotificationShadeWindowViewController(