Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad03d308 authored by Matt Pietal's avatar Matt Pietal
Browse files

Intercept swipe up touches

When NSSL is not a child of NPVC, certain touches will never reach it
as they are now being handled by NSSL first. This primarily includes
swipe up on NSSL, which should dismiss the lockscreen or show the
bouncer.

Flexiglass will eventually replace most of this handling. For now,
move handling up to the parent and delegate back to NPVC, to avoid
a major risky refactoring of touch handling that will only be needed
temporarily.

Bug: 288068119
Test: NotificationShadeWindowViewControllerTest NotificationPanelViewControllerTest
Change-Id: I59538b46f4f87d11ec96aa32884eda1254f8aa0d
parent 3679b887
Loading
Loading
Loading
Loading
+38 −3
Original line number Diff line number Diff line
@@ -594,6 +594,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
    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
@@ -4235,12 +4237,22 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump

    /** Sends an external (e.g. Status Bar) intercept touch event to the Shade touch handler. */
    boolean handleExternalInterceptTouch(MotionEvent event) {
        try {
            mUseExternalTouch = true;
            return mTouchHandler.onInterceptTouchEvent(event);
        } finally {
            mUseExternalTouch = false;
        }
    }

    @Override
    public boolean handleExternalTouch(MotionEvent event) {
        try {
            mUseExternalTouch = true;
            return mTouchHandler.onTouchEvent(event);
        } finally {
            mUseExternalTouch = false;
        }
    }

    @Override
@@ -4868,9 +4880,20 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
    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,
@@ -5024,8 +5047,20 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
            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
+72 −20
Original line number Diff line number Diff line
@@ -266,6 +266,9 @@ public class NotificationShadeWindowViewController implements Dumpable {
        }
        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
@@ -359,10 +362,8 @@ public class NotificationShadeWindowViewController implements Dumpable {
                );

                // 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;
@@ -404,6 +405,15 @@ public class NotificationShadeWindowViewController implements Dumpable {

            @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) {
@@ -430,27 +440,46 @@ public class NotificationShadeWindowViewController implements Dumpable {
                }

                if (mNotificationPanelViewController.isFullyExpanded()
                        && mDragDownHelper.isDragDownEnabled()
                        && !mService.isBouncerShowing()
                        && !mStatusBarStateController.isDozing()) {
                    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 {
                    return false;
                        // This else handles interactions on the full shade while unlocked
                        if (didNotificationPanelInterceptEvent(ev)) {
                            return true;
                        }
                    }
                }
                return false;
            }

            @Override
            public void didIntercept(MotionEvent ev) {
                MotionEvent cancellation = MotionEvent.obtain(ev);
                cancellation.setAction(MotionEvent.ACTION_CANCEL);
                mStackScrollLayout.onInterceptTouchEvent(cancellation);
                if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
                    mNotificationPanelViewController.handleExternalInterceptTouch(cancellation);
                }
                cancellation.recycle();
            }

@@ -460,11 +489,18 @@ public class NotificationShadeWindowViewController implements Dumpable {
                if (mStatusBarStateController.isDozing()) {
                    handled = !mDozeServiceHost.isPulsing();
                }

                if (mStatusBarKeyguardViewManager.onTouch(ev)) {
                    return true;
                }

                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 {
                    if (mDragDownHelper.isDragDownEnabled()
                            || mDragDownHelper.isDraggingDown()) {
                        // we still want to finish our drag down gesture when locking the screen
@@ -473,6 +509,8 @@ public class NotificationShadeWindowViewController implements Dumpable {
                        return handled;
                    }
                }
                return handled;
            }

            @Override
            public void didNotHandleTouchEvent(MotionEvent ev) {
@@ -519,6 +557,20 @@ public class NotificationShadeWindowViewController implements Dumpable {
        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;
    }
+7 −2
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ import com.android.systemui.classifier.Classifier;
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;
@@ -1770,8 +1771,10 @@ public class QuickSettingsController implements Dumpable {
                    // 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.
                    if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
                        mPanelView.getParent().requestDisallowInterceptTouchEvent(true);
                    }
                }
                if (mExpansionAnimator != null) {
                    mInitialHeightOnTouch = mExpansionHeight;
                    mShadeLog.logMotionEvent(event,
@@ -1813,7 +1816,9 @@ public class QuickSettingsController implements Dumpable {
                        && Math.abs(h) > Math.abs(x - mInitialTouchX)
                        && shouldQuickSettingsIntercept(
                        mInitialTouchX, mInitialTouchY, h)) {
                    if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
                        mPanelView.getParent().requestDisallowInterceptTouchEvent(true);
                    }
                    mShadeLog.onQsInterceptMoveQsTrackingEnabled(h);
                    mTracking = true;
                    traceQsJank(true, false);
+3 −1
Original line number Diff line number Diff line
@@ -1545,7 +1545,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
        return (v, event) -> {
            mAutoHideController.checkUserAutoHide(event);
            mRemoteInputManager.checkRemoteInputOutside(event);
            if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
                mShadeController.onStatusBarTouch(event);
            }
            return getNotificationShadeWindowView().onTouchEvent(event);
        };
    }
+12 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ import androidx.test.filters.SmallTest;
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;
@@ -1108,7 +1109,18 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo
        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
Loading